Need help updating old JSP code. Object types in tableData tags - jsf

I am trying to update some old JSF code to run with newer versions of things (JDK 1.8.0_161, Apache Tomcat/8.5.42, javax.faces-2.4.0, javax.servelet.jsp-api-2.3.3)
The dataTable tag is returning the wrong class for the returned data set, String instead of ServerBean.
The specific error is:
reason=500 - javax.servlet.ServletException:
/server.jsp(132,9) '#{m.name}'
Property [name] not found on type [java.lang.String]
I have researched this for 3 full days and have come up empty.
There is JSF with HTML that displays a table with data from a database.
The issue is that the variable that is returned is supposed to be a java class, but it is coming back as a string. I have limited experience with JSF/JSP, but will try to include that I think is relevant.
I have updated all to compile under 1.8
I have updated DTDs and DOCTYPEs
I have updated the serious HTML issues as reported by eclipse Java EE plugin
I have updated the collections in the java
code to be typed: ArrayList to ArrayList<ServerBean>
I have made sure that ServerBean class is on the classpath <%# page import="com.xxx.yyy.beans.ServerBean"%>
JSP:
<h:dataTable>
</h4> <h:dataTable id="servers" value="#{serverdefn.serverList}" var="m" styleClass="font1">
<h:column>
<h:outputLink value="#{m.name}" />
<h:outputText value="#{m.name}" />
</h:column>
</h:dataTable>
WEB-INF/server-defn.xml:
<managed-bean>
<managed-bean-name>server1</managed-bean-name>
<managed-bean-class>com.xxx.yyy.beans.ServerBean</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>name</property-name>
<value>Local</value>
</managed-property>
...
</managed-bean>
<managed-bean>
<managed-bean-name>serverlist</managed-bean-name>
<managed-bean-class>java.util.ArrayList</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<list-entries>
<value>#{server1}</value>
<value>#{server2}</value>
</list-entries>
</managed-bean>
ServerBean.java:
protected ArrayList<ServerBean> serverList;
public ArrayList<ServerBean> getServerList() {
return serverList;
}
As the previous implementation worked, I believe it would bring the variable m as a ServerBean. The new stuff is bringing it in as a String.
Where/how does one specify the type of the object that is returned?
I was hoping that adding types to the java collections in ServerBean.java would trigger that, but it did not. I also looked to see if I should do something in the XML, but it doesn't seem so.

Related

How to use component binding in JSF right ? (request-scoped component in session scoped bean)

Mojara 2.1.21
I've updated my question based on comments. I have two situation where a component is bound to server session bean. (Additional links with information: Binding attribute causes duplicate component ID found in the view and https://stackoverflow.com/a/12512672/2692917)
Version 1:
single.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 2:
template.xhtml:
<h:outputText value=... binding="#{mysessionbean.out}"
view1.xhtml:
<ui:composition template="template.xhtml" />
view2.xhtml:
<ui:composition template="template.xhtml" />
java:
#SessionScoped #Named public class Mysessionbean {
UIOutput out;
//getter and setter ....
}
Version 1 is ok. (At least I've not encounter any errors so far). But in version 2 the duplicate id error is occured if I navigate from one page to another. Why does it happen ?
Is it safe to use (request-scoped) component (in version 1) with session scoped binding ?
Are there another use cases to consider ?
Edit:
Functional requirement 1:
I want to use Primefaces datatable in a view. I need some info from this datatable. (Such as selected row or row index). So binding the datatable helps me to retrieve this info.
Functional requirement 2:
Components binding in composite components. They will be bound to session scoped bean. (And used mainly on one page, but what if I used it on another page ?
Requirements 3
The situation as in "Version 2". Template with primefaces menu and session scoped binding. For this I've used the EL-Binding.
In JSF 2.x, unless you want to manipulate components programmatically (which is at its own also rather fishy), there is no sensible real world use case to bind components to a backing bean. For sure not if they are further not been used in the backing bean itself, or if it are solely their attributes which are been flattened out.
As to the functional requirement of getting the current row of the data table, there are much better ways listed here, How can I pass selected row to commandLink inside dataTable?, for example if your environment supports EL 2.2:
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<h:commandLink value="Foo" action="#{bean.foo(item)}" />
The two last requirements are totally unclear. At least, if you're doing something like:
<x:someComponent binding="#{bean.someComponent}" />
with in bean
someComponent.setSomeAttribute(someAttribute);
someComponent.setOtherAttribute(otherAttribute);
then you should instead be doing
<x:someComponent someAttribute="#{bean.someAttribute}" otherAttribute="#{bean.otherAttribute}" />
Or, if you intend to be able to use the component somewhere else in the view like so
<h:inputText ... required="#{not empty param[bean.save.clientId]}" />
...
<h:commandButton binding="#{bean.save}" ... />
and the instance is further nowhere been used in the bean, then just get rid of the unnecessary property altogether:
<h:inputText ... required="#{not empty param[save.clientId]}" />
...
<h:commandButton binding="#{save}" ... />
If there is really, really no way for some unclear reason, then split all request scoped properties of the session scoped bean out into a separate request scoped bean which you in turn bind to form actions. The session scoped one can just be injected as a #ManagedProperty of the request scoped one.
See also:
Binding attribute causes duplicate component ID found in the view
How does the 'binding' attribute work in JSF? When and how should it be used?
We ran into a similar problem and I just want to share our solution:
Problem:
In a view there was a (extended largely customized) datatable.
<x:dataTable binding="#{bean.someSomeDataTable}" />
After navigating to another page and back we wanted the datatable to have the exact same state. Previously we solved that by binding the datatable to to backing bean. This worked fine with JSPs. With Facelets we could not do that (Duplicate ID errors). So we used the binding, but only saved/restored the state of the datatable component.
public HtmlDataTable getSomeDataTable()
{
HtmlDataTable htmlDataTable = new HtmlDataTable();
if (tableState != null)
htmlDataTable.restoreState(FacesContext.getCurrentInstance(), tableState);
return htmlDataTable;
}
public void setSomeDataTable(HtmlDataTable table)
{
tableState = table.saveState(FacesContext.getCurrentInstance());
}

jsf send selectOneMenu value as direct request managed bean

I have a selectOneMenu that manages a relation between two Objects A and B.
Where A is fixed and B is selectable via the menu.
On form submit B is send to the bean for further processing (creating and saving relationship object AToB).
Not working case!
<h:selectOneMenu value=#{b}>
<!-- b items from bean -->
</h:selectOneMenu>
<h:commandButton action="#{bean.addBToSelA(b)}"/>
<managed-bean>
<description>B Entity Request Bean</description>
<managed-bean-name>b</managed-bean-name>
<managed-bean-class>B</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Working case!
But if the selectOneMenu value is a nested property of a different managed bean it works. (as example AToB)
<h:selectOneMenu value=#{aToB.b}>
<!-- b items from bean -->
</h:selectOneMenu>
<h:commandButton action="#{bean.addBToSelA(aToB.b)}"/>
<managed-bean>
<description>AToB Entity Request Bean</description>
<managed-bean-name>aToB</managed-bean-name>
<managed-bean-class>AToB</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Note: It is enough if my "b" is just a property of a different request managed bean.
Can someone be so kind and explain why?
Because JSF has already created the bean instance beforehand. It won't be overridden with the model value if the instance already exist in the scope. Remove the <managed-bean> from faces-config.xml and it'll work just fine.
Unrelated to the concrete problem, you seem to be already using JSF 2.x. Why sticking to the old JSF 1.x style faces-config.xml configuration? Just use #ManagedBean annotation (on real backing bean classes only, of course).

JSF accessing backing map object

I have a jsp subview page that I have passed a parameter to and I want to then pass that parameter to a map's get() method that is stored in a session bean.
Ex:
<h:panelGrid id="panelGrid1" rendered="#{MySessionBean[param.id].showPanelGrid1}">
...
</h:panelGrid>
In the above example MySessionBean implements the Map interface and I have my own custom get method that will create an object and put it in the map if none exists for the key [params.id]. When I run the code in debug mode my get method for MySessionBean never gets called and my panel is always rendered. Am I not passing parameters correctly? Or accessing the parameter passed to the subview correclty?
Here is how I passed the parameter to this subview:
<f:subview id="subview1">
<jsp:include page="/MyTemplatePage.jsp">
<jsp:param name="id" value="staticUniqueId1"/>
</jsp:include>
</f:subview>
The reason I'm trying to do this is so I can include this template subview multiple times in a single page so that each instance won't have the same backing bean objects. Thus using a map in the session and passing it an id to gain access to the backing beans for each instance.
Also, I am limited JSF 1.2, JSTL 1.1, JBoss 4.0.4. So I can't use answers that use RichFaces or JSF 2.
EDIT: 11/22/11 11:23
I Replaced the [param.id] with a static string value.
<h:panelGrid id="panelGrid1" rendered="#{MySessionBean.MY_TEMP_VAL.showPanelGrid1}">
...
</h:panelGrid>
And everything worked. It triggered my map get method and accessed the session beans and everything. So it is clearly not liking the whole using [params.id] passing to the map object. Not sure what to do from here.
In JSF2 the proper and easy solution would be to use composite components. Since you are stuck with JSF 1.2 and jsp you could use tag files instead. These are like regular jsps but with the extension tag or tagx and placed under WEB-INF/tags. I'm using the xml syntax in the example below, in a file name example.tagx:
<jsp:root version="2.1"
xmlns:jsp="http://java.sun.com/JSP/Page"
xmlns:h="http://java.sun.com/jsf/html">
<jsp:directive.attribute name="myBean"
required="true"
rtexprvalue="false"
deferredValue="true"
deferredValueType="com.example.MyBean"/>
<h:panelGrid id="panelGrid1" rendered="#{myBean.showPanelGrid1}">
...
</h:panelGrid>
</jsp:root>
In a jspx you then have to declare the namespace like xmlns:myTags="urn:jsptagdir:/WEB-INF/tags/", in a jsp the syntax would be:
<%#taglib tagdir="/WEB-INF/tags" prefix="myTags" %>
The custom tag can then be used multiple times on a page and the right backing bean can be passed as an attribute like this:
<myTags:example myBean="#{myBeanInstance1}" />
Edit: You might also need a file WEB-INF/tags/implicit.tld to specify the version:
<?xml version = '1.0' encoding = 'UTF-8'?>
<taglib xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
version="2.1" xmlns="http://java.sun.com/xml/ns/javaee">
<tlib-version>2.1</tlib-version>
</taglib>

JSF2.0, how commandButton knows which bean to send this

I am starting in JSF2, comming from spring mvc, so I have some doubts that I cannot find answers on Core JavaServer Faces v3
Like this one...
How can the tag h:commandButton know which bean I am talking about ? I can only have one Bean per JSF page, is that it ? I am only giving it a msg.next which is a text from a i18n file.(quizbean is my bean)
<h:body>
<h:form>
<h3>#{msgs.heading}</h3>
<p>
<h:outputFormat value="#{msgs.currentScore}">
<f:param value="#{quizBean.score}"/>
</h:outputFormat>
</p>
<p>#{msgs.guessNext}</p>
<p>#{quizBean.current.sequence}</p>
<p>
#{msgs.answer}
<h:inputText value="#{quizBean.answer}"/>
</p>
<p><h:commandButton value="#{msgs.next}"/></p>
</h:form>
The command button does not need to know this. All it generates is a HTML <input type="submit"> element. This is embedded in a HTML <form> with an action URL pointing to the same URL as the page. There's further also the <input type="hidden" name="javax.faces.ViewState">. Thanks to this field, JSF knows exactly what view you're submitting to. This view holds information about all inputs. This view knows that there's an <h:inputText value="#{quizBean.answer}" />. The view knows the field name of the generated HTML <input type="text"> element. JSF will get the submitted request parameter value by request.getParameter() using this name and then update the answer property of the current instance of quizBean with this value.
Rightclick the page in your browser and choose View Source to see the JSF-generated HTML output. Put a breakpoint on ApplyRequestValuesPhase#execute() and HtmlBasicRenderer#decode() methods (assuming that you're using Mojarra not MyFaces) to track the gathering of submitted values for every UIComponent in the view.
The bean has to be managed by JSF, then it will know which bean you are talking about.
e.g.
<f:param value="#{quizBean.score}"/>
Here, the bean quizBean is a Managed-Bean, managed by JSF.
And to make it a managed bean you to tell JSF about it by either using annotations as follows -
#ManagedBean(name="quizBean") //name is optional or you give your own name to the bean
#SessionScoped //tell JSF in which scope you want to keep your managedbean
public class QuizBean {
//....
Or by mentioning it as follows in the JSF configuration file (faces-config.xml) -
<managed-bean>
<managed-bean-name>quizBean</managed-bean-name>
<managed-bean-class>com.pkg.QuizBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
//Older versions of JSF requires this where annotations do not work
//But if you are using JSF 2.0 then it's a lot better to use annotations
You can use more than one beans in a view (page).
If this is an example from Core Java Server Faces, then read more carefully, it explains everything.
msgs as far as I remember, refers to message bundle, declared in faces-config.xml.
As for your question how commandButton knows which bean to call. In your example, the class name QuizBean, most likely correspond to the bean with the same name. That's enough for JSF 2.0. However, you could change that name by 2 methods:
1) If you use JSF managed beans, you should go like this:
#ManagedBean(name="quiz")
#ViewScoped
public class QuizBean { }
2) If you use CDI-beans you would do this:
#Named("quiz")
#RequestScoped
public class QuizBean {}
Remember that CDI-beans scope annotations come from package javax.enterprise.context. And JSF scopes are in the javax.faces.bean package. Do not mix them!
Update:
Please refer to page 35 of the book Core Java Server Faces 3rd Edition for more details about your question and do not hurry to ask questions if you don't understand something right away.

JSF bookmarking problem

I have a h:datatable that display employees data.
I want the user when click the employee name to navigate to a new page which URL looks like
employees?id=<some id>
I've tried to combine JSP EL with JSF EL, but no way out.
If you're not on JSF 2.0 yet, then you can just make use of h:outputLink in combination with <f:param>, #{param} and faces-config.xml.
Basic table example:
<h:dataTable value="#{bean.employees}" var="employee">
<h:column>
<h:outputLink value="employees.jsf">
<f:param name="id" value="#{employee.id}" />
<h:outputText value="View employee #{employee.name}" />
</h:outputLink>
</h:column>
</h:dataTable>
Basic faces-config.xml example:
<managed-bean>
<managed-bean-name>employeeManager</managed-bean-name>
<managed-bean-class>com.example.EmployeeManager</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>id</property-name>
<value>#{param.id}</value>
</managed-property>
</managed-bean>
Basic com.example.EmployeeManager example:
public class EmployeeManager {
private Long id;
private Employee employee;
#PostConstruct
public void init() {
this.employee = employeeDAO.find(this.id);
}
}
The #PostConstuct annotated methods will be invoked after bean construction and all of injection and managed property setting. Also see this article for more info and examples.
There are two possible solutions I can think of:
Use JSF 2 (part of Java EE 6)
If you are stuck in JSF 1.x, use PrettyFaces.
If it's possible to switch to a Java EE 6 server, I highly recommend option number 1.
Edit: There are 2 tags that were added in JSF 2: <h:link /> and <h:button />. These use GET instead of POST. Also, look into <f:viewparam />. On top of this, there are many other wonderful additions in JSF 2. For a brief overview, see this article.

Resources