JSF Property references object in a scope with shorter lifetime than the target scope view - jsf

I have a view-scoped managed bean with a managed property bound to a querystring parameter. JSF gives me the familiar exception:
javax.faces.FacesException:
Property reset references object in a scope with shorter lifetime than the target scope session
For example:
<managed-bean>
<managed-bean-name>userBean</managed-bean-name>
<managed-bean-class>project.UserBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-property>
<property-name>reset</property-name>
<value>#{param['reset']}}</value>
</managed-property>
</managed-bean>
Any idea to solve this?

This is by design. The managed property cannot have a scope which is narrower than the scope of the managed bean itself. The managed property is only set during bean's construction (which is in your case thus the start of a view), but in any subsequent request within the same view scope the request parameter may not be valid anymore and the bean would possibly become in an invalid state. This design limitation prevents that.
To achieve the particular functional requirement anyway, just use <f:viewParam> instead.
<f:metadata>
<f:viewParam name="reset" value="#{userBean.reset}" />
</f:metadata>
See also:
ViewParam vs #ManagedProperty(value = "#{param.id}")

Related

View scope: java.io.NotSerializableException: javax.faces.component.html.HtmlInputText

There is an error each time a button calls an action from the backing-bean.
Only applies to beans with a view scope and I haven't found a way to fix it without regression over other modules in the code.
DefaultFacele E Exiting serializeView - Could not serialize state: javax.faces.component.html.HtmlInputText
java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
Or also:
com.ibm.ws.webcontainer.servlet.ServletWrapper service SRVE0014E: Uncaught service() exception
root cause Faces Servlet: ServletException: /jspFiles/jsf/Deployments/editQueue.faces No saved view state could be found for the view identifier /jspFiles/jsf/Deployments/editQueue.faces
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:205)
Caused by: javax.faces.application.ViewExpiredException: /jspFiles/jsf/Deployments/editQueue.faces No saved view state could be found for the view identifier: /jspFiles/jsf/Deployments/editQueue.faces
at org.apache.myfaces.lifecycle.RestoreViewExecutor.execute (RestoreViewExecutor.java:128)
faces-config.xml
<managed-bean>
<managed-bean-name>pc_EditQueue</managed-bean-name>
<managed-bean-class>pagecode.jspFiles.jsf.deployments.EditQueue</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-property>
<property-name>queueDeploymentBean</property-name>
<value>#{queueDeploymentBean}</value>
</managed-property>
</managed-bean>
web.xml
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>server</param-value>
</context-param>
<context-param>
<param-name>org.apache.myfaces.SERIALIZE_STATE_IN_SESSION</param-name>
<param-value>true</param-value>
</context-param>
bean:
#ManagedBean
#ViewScoped
public class EditQueue extends PageCodeBase implements Serializable {
private static final long serialVersionUID = -1L;
public String doButtonAddAction() {
// calls manager (long)
FacesUtil.setViewMapValue("queueDeploymentBean", queueDeploymentBean);
return "";
}
I read this suggestion to set SERIALIZE_STATE_IN_SESSION to false and indeed this solution works for this view scope bean. However this fix comes at a high cost: many existing modules in the application don't work anymore so I cannot use this fix there. Some of the regression observed are:
// returns null must be changed with FacesUtil.getSessionMapValue("userId");
getSessionScope().get("userId");`
// returns null must be changed with FacesUtil.getViewMapValue("linkerBean");
linkerBean = (Linker) getManagedBean("linkerBean");`
// NPE so must be changed with FacesContext.getCurrentInstance().addMessage(...)
getFacesContext().addMessage(...)`
So my questions are:
why the NotSerializableException even though the bean implements Serializable ?
is there a way to apply the SERIALIZE_STATE_IN_SESSION param over only a subset of the beans or not ?
is there another solution to have my view scope bean to work (without having to change them to request scope or else) ?
WebSphere 8.0.0.3,
Java 1.6.0,
JSF 2.0,
RichFaces 4.2.3.Final
why the NotSerializableException even though the bean implements Serializable ?
Not only the bean needs to be serializable, but all of its properties (and all their nested properties etc) must also be serializable. The name of the offending non-serializable class can easily be found in the exception message:
java.io.NotSerializableException: javax.faces.component.html.HtmlInputText
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
This suggests that you're binding a <h:inputText> component to the bean like below:
<h:inputText binding="#{bean.fooInput}" ...>
private UIComponent fooInput;
This is indeed illegal when the bean is not in request scope. UIComponent instances are request scoped and may not be shared across multiple requests. Moreover, UIComponent instances are not serializable. Only their state is, but JSF will worry about that all by itself.
You must remove the fooInput property and you need to look for a different solution for the problem for which you incorrectly thought that binding the component to a view scoped bean would be the right solution.
If you intend to access it elsewhere in the view, e.g. #{bean.fooInput.value}, then just bind it to the Facelet scope without the need for a bean property:
<h:inputText binding="#{fooInput}" ...>
It'll be available elsewhere in the same view via #{fooInput.xxx}.
<h:inputText ... required="#{empty fooInput.value}" />
If you intend to set some component attribute programmatically inside the bean, e.g. fooInput.setStyleClass("someClass"), or fooInput.setDisabled(true), then you should be binding the specific attribute in the view instead of the whole component:
<h:inputText ... styleClass="#{bean.styleClass}" />
...
<h:inputText ... disabled="#{bean.disabled}" />
If you are absolutely positive that you need to get a hand of whole UIComponent instance in the bean for whatever reason, then manually grab it in method local scope instead of binding it:
public void someMethod() {
UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
UIComponent fooInput = view.findComponent("formId:fooInputId");
// ...
}
But better ask a question or search for an answer how to solve the concrete problem differently without the need to grab a whole component in the backing bean.
See also:
How does the 'binding' attribute work in JSF? When and how should it be used?
As to the ViewExpiredException, this has different grounds which is further elaborated in javax.faces.application.ViewExpiredException: View could not be restored.

Communication between two beans

I have two region and two taskflow on a page. On first taskflow manage bean is on pageflow scope where in second taskflow its on backing bean scope. My requirement is I want to call method of one bean from econd bean and vice-versa.
For example: on first jsff if some action happen then it action will go to its bean and from there I need to call method of second bean and vice-versa.
How can I achieve this?
Since both task flow will be running at same time so I need to get running instance of bean so that I can get the current status/value UI components.
All you need to do is to inject the bean whose method you want to use in the other bean. In ADF there is an easy way to achieve this. You should have a file called adfc-config.xml inside your WEB-INF folder. If you open it's source, you'll notice that each bean is described inside the <managed-bean> tag. It will be something like:
<managed-bean id="__2">
<managed-bean-name>bean1</managed-bean-name>
<managed-bean-class>com.domain.Bean1</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
for each bean. You have to insert a <managed-property> tag inside with a reference of the bean you want to inject, just like this:
<managed-bean id="__2">
<managed-bean-name>bean1</managed-bean-name>
<managed-bean-class>com.domain.Bean1</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-property>
<property-name>bean2</property-name>
<value>#{Bean2}</value>
</managed-property>
</managed-bean>
Also, inside the Bean1 class you have to create an instance variable of Bean2, and then you can use it to get its current state.

JSF Managed bean and managed property both necessary?

I'm new to JSF and was wondering:
If I have a controller that handles all the work for a given page and a bean that holds all the data for said page, is It necessary to have both the
#ManagedProperty(value="#{myBean}")
annotation on the controller and the
#ManagedBean(name="myBean")
#SessionScoped
annotations on the form bean?
Managed beans in JSF are used to store the state of a web page. The JSF implementation is responsible for creating and discarding the bean objects( hence the name managed bean).
For every class you write #ManagedBean, the bean object is created by the JSF implementation as and when it detects an usage of the bean with the name(you can either sepcify a bean name or leave it to JSF to use the default name-class name with the first character changed to lowercase). The object created is placed in a map of the specified scope. Each scope has a map that it uses to store bean objects which have that scope specified.
Now if you need the values of these beans in your controller, you have to inject it using the ManagedProperty annotation. Note that you would need to provide the controller with a setter method for the managedProperty.
So to answer your question, the managedBean annotation is required to tell the JSF implementation to manage the bean instance and store the values in the table specific to the session scope. And the ManagedProperty annotation is needed to use that bean stored in the current session so that you can access all of its values.
We use #ManagedBean annotation to register a java bean with a JSF framework. This is a replacement for a faces-config.xml <managed-bean> element. We typically do not use name attribute because it already defaults to a simple class name camel cased.
We use #RequestScope and other scope annotations to explicitly specify the scope we want via annotation. This is equivalent to specifying<managed-bean-scope> xml entry. If you don't specify the scope it will be defaulted to #NoneScoped.
We use #ManagedProperty and specify an EL-expression in its value attribute to use JSF-provided dependency injection engine for JSF artifacts like other managed beans with broader scopes and EL-defined variables like param. We do it in case we need the injected values in other JSF artifacts, most typically beans. The injected values are available in bean's #PostConstruct-annotated method. This is an alternative to <managed-property> xml entry.
To sum it up. Use #ManagedBean #RequestScoped to register a bean with JSF framework. Use #ManagedProperty inside this bean to be able to reference among others other JSF beans with the same or broader scopes in this bean. In case you don't need to reference other beans in the created bean you don't need to use the #ManagedProperty annotation as it's purely optional.

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).

How to pass url parameters to JSF?

I haven't managed to find a way to pass parameters to JSF pages through URL parameters.
http://www.example.com/jsfApp.jsp?param1=value1&param2=value2
Could someone point me at the right direction with this?
As you're using JSPs, I'll assume that you're using JSF 1.x.
To create a link with query parameters, use h:outputLink with f:param:
<h:outputLink value="page.jsf">
<f:param name="param1" value="value1" />
<f:param name="param2" value="value2" />
</h:outputLink>
The value can be set dynamically with help of EL.
To set them in the managed bean automagically, you need to define each as managed-property in faces-config.xml:
<managed-bean>
<managed-bean-name>bean</managed-bean-name>
<managed-bean-class>com.example.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>param1</property-name>
<value>#{param.param1}</value>
</managed-property>
<managed-property>
<property-name>param2</property-name>
<value>#{param.param2}</value>
</managed-property>
</managed-bean>
The imlicit EL variable #{param} refers to the request parameter map as you know it from the Servlet API. The bean should of course already have both the param1 and param2 properties with the appropriate getters/setters definied.
If you'd like to execute some logic directly after they are been set, make use of the #PostConstruct annotation:
#PostConstruct
public void init() {
doSomethingWith(param1, param2);
}
For more hints about passing parameters and that kind of stuff around in JSF, you may find this article useful.
The JSF 2.x approach would be using either #ManagedProperty in the backing bean class, or <f:viewParam> in the target view. See also this question: ViewParam vs #ManagedProperty(value = "#{param.id}")

Resources