I'm using JSF 2.2 / Mojarra 2.2.8
In my model there are java.util.Set
and I want to edit those Set
public class MyModel {
private Set<Foo> fooSet;
private Set<Bar> barSet;
// getters and setters
}
public class Foo {
private String label;
//getter and setter
}
public class Bar {
private String name;
// getter and setter
}
I'm using composite component for that
<h:form>
<ez:editFooSet myModel="#{someBean.myModel}"/>
<ez:editBarSet myModel="#{someBean.myModel}"/>
<!-- ... -->
</h:form>
My idea is to store a List needed by the ui:repeat
in a JSF ManagedBean and use a @FacesComponent
to convert the Set
to List
in encodeBegin()
and the List
to Set
in updateModel()
editFooSet.xhtml :
<cc:interface componentType="my.app.component.FooSetComponent">
<cc:attribute name="myModel" type="my.app.model.MyModel" required="true"/>
</cc:interface>
<cc:implementation>
<ui:repeat value="#{fooSetBean.value}" var="item">
<h:outputLabel value="Foo label: "/>
<h:inputText value="#{item.label}"/>
<h:commandButton value="remove" action="#{fooSetBean.remove(item)}"/>
</ui:repeat>
<h:commandButton value="add" action="#{fooSetBean.add()}"/>
</cc:implementation>
FooSetBean.java
@Named
@ViewScoped
public class FooSetBean {
private List<Foo> value;
// getter and setter
puvlic void remove(Foo foo) {
fooList.remove(foo);
}
public void add() {
fooList.add(new Foo());
}
}
and the FooSetComponent.java :
@FacesComponent("my.app.component.FooSetComponent")
public class FooSetComponent extends UIInput implements NamingContainer {
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
@Override
public Object getSubmittedValue() {
return null;
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
MyModel model = (MyModel) super.getAttributes().get("myModel");
Collection<Foo> foos = model.getFooSet();
List<Foo> fooList = new ArrayList<>(foos);
FooSetBean bean = context.getApplication().evaluateExpressionGet(context, "#{fooSetBean}", FooSetBean.class) ;
bean.setValue(fooList);
super.encodeBegin(context);
}
@Override
public void updateModel(FacesContext context) {
MyModel model = (MyModel) super.getAttributes().get("myModel");
FooSetBean bean = context.getApplication().evaluateExpressionGet(context, "#{fooSetBean}", FooSetBean.class) ;
Collection<Foo> newValue = bean.getValue();
model.setFooSet(new HashSet<>(newValue));
}
}
and the same for editBarSet.xhtml, BarSetBean.java and BarSetComponent.java
And that solution is working
My problem is that I have a lot of those Set
and I want to factorize this code
I want to have something like that :
<h:form>
<ez:editRepeat value="#{someBean.myModel.fooSet}" itemClass="#{Foo.class}">
<h:outputLabel value="Foo label: "/>
<h:inputText value="#{item.label"/>
</ez:editRepeat>
<ez:editRepeat value="#{someBean.myModel.barSet}" itemClass="#{Bar.class}">
<h:outputLabel value="Bar name: "/>
<h:inputText value="#{item.name}"/>
</ez:editRepeat>
<!-- ... -->
</h:form>
with the editRepeat.xhtml :
<cc:interface componentType="my.app.component.EditRepeatComponent">
<cc:attribute name="value" type="java.util.collection" required="true"/>
<cc:attribute name="itemClass" type="java.lang.Class" required="true"/>
</cc:interface>
<cc:implementation>
<ui:repeat value="#{fooSetBean.value}" var="item" id="repeat">
<cc:insertChildren/>
<h:commandButton value="remove" action="#{cc.remove(item)}"/>
</ui:repeat>
<h:commandButton value="add" action="#{cc.add()}"/>
</cc:implementation>
with a EditRepeatComponent.java
@FacesComponent("my.app.component.EditRepeatComponent")
public class EditRepeatComponent extends UIInput implements NamingContainer {
@Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
@Override
public void encodeBegin(FacesContext context) throws IOException {
Collection value = (Collection) super.getAttributes().get("value");
List<Foo> list = new ArrayList<>(value);
setList(list);
super.encodeBegin(context);
}
public List getList() {
return (List) getStateHelper().get("list");
}
public void setList(List list) {
getStateHelper().put("list", list);
}
public void add() {
try {
Class itemClass = (Class) super.getAttributes().get("itemClass");
Object newItem = itemClass.newInstance();
getList().add(newItem);
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
public void remove(Object item) {
getList().remove(item);
}
@Override
public void updateModel(FacesContext context) {
// ???
}
@Override
public Object getSubmittedValue() {
// ???
}
}
But that doesn't work After a few seconds (the system works during 1 second) I have an exeption :
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.rangeCheck(ArrayList.java:653)
at java.util.ArrayList.get(ArrayList.java:429)
at javax.faces.component.AttachedObjectListHolder.restoreState(AttachedObjectListHolder.java:166)
at javax.faces.component.UIComponentBase.restoreState(UIComponentBase.java:1611)
at com.sun.faces.application.view.FaceletPartialStateManagementStrategy$2.visit(FaceletPartialStateManagementStrategy.java:380)
at com.sun.faces.component.visit.FullVisitContext.invokeVisitCallback(FullVisitContext.java:151)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1689)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700)
at com.sun.faces.application.view.FaceletPartialStateManagementStrategy.restoreView(FaceletPartialStateManagementStrategy.java:367)
at com.sun.faces.application.StateManagerImpl.restoreView(StateManagerImpl.java:138)
at com.sun.faces.application.view.ViewHandlingStrategy.restoreView(ViewHandlingStrategy.java:123)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.restoreView(FaceletViewHandlingStrategy.java:585)
at com.sun.faces.application.view.MultiViewHandler.restoreView(MultiViewHandler.java:150)
at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:353)
at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:353)
at javax.faces.application.ViewHandlerWrapper.restoreView(ViewHandlerWrapper.java:353)
at org.omnifaces.viewhandler.RestorableViewHandler.restoreView(RestorableViewHandler.java:86)
at com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:197)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:121)
at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:198)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:646)
at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85)
at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61)
at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:131)
at io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:56)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45)
at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:63)
at io.undertow.security.handlers.AuthenticationMechanismsHandler.handleRequest(AuthenticationMechanismsHandler.java:58)
at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70)
at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:261)
at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:247)
at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:76)
at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:166)
at io.undertow.server.Connectors.executeRootHandler(Connectors.java:197)
at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:759)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
And I don't understand why
And I don't know yet how to implements updateModel()
or getSubmittedValue()
to make all the system working