Reputation: 873
We are migrating a JSF 2.1 application, from JBoss AS 7.2 to Wildfly and thus JSF 2.2. The problem We're having is the following: We have a compositecomponent that is included in a @ViewScoped
bean. The component has to retain its value through multiple requests, so a Request Scoped bean is not a solution.
The exception we're getting is a multiple component id one. After the request JSF starts to render the component for the second time, and fails.
I made a simple demo for this:
MyViewBean.java
@ViewScoped
@Named
public class MyViewBean implements Serializable {
private Component component;
public Component getComponent() {
return component;
}
public void setComponent(Component component) {
this.component = component;
}
public String increment(){
component.setCounter(component.getCounter()+1);
return "";
}
}
Component.java
@FacesComponent(value = "composite")
public class Component extends UINamingContainer {
private Integer counter = 0;
public Integer getCounter() {
return counter;
}
public void setCounter(Integer counter) {
this.counter = counter;
}
}
compositeTest.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
xmlns:f="http://xmlns.jcp.org/jsf/core"
xmlns:h="http://xmlns.jcp.org/jsf/html"
template="/WEB-INF/templates/default.xhtml"
xmlns:pelda="http://xmlns.jcp.org/jsf/composite/component">
<ui:define name="content">
<h1>Composite component Test!</h1>
<h:form>
<pelda:composite binding="#{myViewBean.component}" />
<h:commandButton action="#{myViewBean.increment()}" value="Push me!"/>
</h:form>
</ui:define>
</ui:composition>
composite.xhtml
<cc:interface componentType="composite">
</cc:interface>
<cc:implementation>
<h:outputText id="id_hello" value="Helloka" />
<h:outputText id="id_counter" value="#{cc.counter}" />
</cc:implementation>
</html>
How to achieve that the counter can be incremented (with @RequestScoped bean it resets) and won't fail with idUniqueness error? We're using Mojarra 2.2.8 (Default in wildfly), also tried with Mojarra 2.2.12 (the latest as per writing this).
Thanks in advance!
Upvotes: 1
Views: 422
Reputation: 1108632
UIComponent
instances are inherently request scoped. You should never reference UIComponent
instances beyond the request scope. Carefully read How does the 'binding' attribute work in JSF? When and how should it be used? for an elaborate explanation on that.
You only want to save its state in the JSF state via the inherited getStateHelper()
method. This acts basically as the view scope.
@FacesComponent(value = "composite")
public class Component extends UINamingContainer {
public Integer getCounter() {
return (Integer) getStateHelper().eval("counter", 0);
}
public void setCounter(Integer counter) {
getStateHelper().put("counter", counter);
}
}
Don't forget to get rid of the binding
attribute in the view.
Upvotes: 1