javax.el.PropertyNotFoundException when submitting

2019-01-18 07:57发布

问题:

In my backing-bean I have a collection of objects of different subclasses sharing a common interface. Inside the view, an ui:repeat iterates over this collection. Inside this loop, different properties have to be rendered depending on the concrete implementation of the interface.

I reduced the problem to the following backing bean:

@Named
@SessionScoped
public class DummyBean implements Serializable {
    private List<Type> objects = new ArrayList<Type>();

    public void add1() {
        objects.add(new Type1());
    }

    public void add2() {
        objects.add(new Type2());
    }

    public void remove(Type o) {
        objects.remove(o);
    }

    // Getter.
}

And the following Type implementations which are added by the methods add1 and add2. They have some common properties, but they may also have different ones, such as getType1OnlyMethod() in below example:

public class Type1 implements Type {
    @Override
    public String getType() { return "1"; }

    public List<String> getType1OnlyMethod() {
        return Arrays.asList("only1", "only2");
    }

    // ...
}
public class Type2 implements Type {
    @Override
    public String getType() { return "2"; }

    // ...
}

In the view I want to iterate over all objects which are stored in the DummyBean and display their contents. Depending on the concrete type of the object, the method which is only implemented in the class Type1 may be called using the rendered-attribute for conditional rendering:

<h:form id="dummyForm">
  <ui:repeat value="#{dummyBean.objects}" var="_obj" >
    <h:outputText value="Type of the Object is #{_obj.type}." />
    <h:panelGroup rendered="#{_obj.type eq '1'}">
      <ui:repeat value="#{_obj.type1OnlyMethod}" var="_oneOnlyObject" varStatus="_status" >
        <h:outputText value="#{_oneOnlyObject}" />
      </ui:repeat>
    </h:panelGroup>
    <h:commandLink value="remove" action="#{dummyBean.remove(_obj)}">
      <f:ajax render="dummyForm" />
    </h:commandLink>
    <br/>
  </ui:repeat>

  <h:commandLink value="add1" action="#{dummyBean.add1}">
    <f:ajax render="dummyForm" />
  </h:commandLink>
  <br/>
  <h:commandLink value="add2" action="#{dummyBean.add2}">
    <f:ajax render="dummyForm" />
  </h:commandLink>
</h:form>

Using the h:commandLinks on the page I can add and remove Type1 objects at will. If I add Type2 objects, they are rendered as expected. But when I try to remove one of the Type2 objects, I get an exception in the render-response phase (nevertheless if there are other elements in the list or not):

2014-03-24 15:42:46,754 SEVERE [javax.enterprise.resource.webcontainer.jsf.application] (default task-11) Error Rendering View[/transition/beginTestSite.xhtml]:
   javax.el.PropertyNotFoundException: /transition/beginTestSite.xhtml @23,96 value="#{_obj.type1OnlyMethod}": The class 'at.co.xss.Type2' does not have the property 'type1OnlyMethod'.
        at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:111) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.facelets.component.UIRepeat.getValue(UIRepeat.java:279) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.facelets.component.UIRepeat.getDataModel(UIRepeat.java:255) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.facelets.component.UIRepeat.setIndex(UIRepeat.java:523) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.facelets.component.UIRepeat.doVisitChildren(UIRepeat.java:790) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.facelets.component.UIRepeat.visitTree(UIRepeat.java:748) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at com.sun.faces.facelets.component.UIRepeat.visitTree(UIRepeat.java:754) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at javax.faces.component.UIForm.visitTree(UIForm.java:371) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at javax.faces.component.UIComponent.visitTree(UIComponent.java:1700) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at com.sun.faces.application.view.FaceletPartialStateManagementStrategy.saveView(FaceletPartialStateManagementStrategy.java:472) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.application.StateManagerImpl.saveView(StateManagerImpl.java:89) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at javax.faces.application.StateManager.getViewState(StateManager.java:593) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at com.sun.faces.context.PartialViewContextImpl.renderState(PartialViewContextImpl.java:486) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.context.PartialViewContextImpl.processPartial(PartialViewContextImpl.java:328) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at javax.faces.context.PartialViewContextWrapper.processPartial(PartialViewContextWrapper.java:219) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at org.primefaces.context.PrimePartialViewContext.processPartial(PrimePartialViewContext.java:57) [primefaces-4.0.jar:4.0]
        at org.richfaces.context.ExtendedPartialViewContextImpl.processPartial(ExtendedPartialViewContextImpl.java:218) [richfaces-core-impl-4.3.5.Final.jar:4.3.5.Final]
        at javax.faces.component.UIViewRoot.encodeChildren(UIViewRoot.java:1004) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1856) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:435) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:133) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at javax.faces.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:337) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:120) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:219) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at javax.faces.webapp.FacesServlet.service(FacesServlet.java:647) [jboss-jsf-api_2.2_spec-2.2.5.jar:2.2.5]
        at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:130) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:449) [shiro-web-1.2.2.jar:1.2.2]
        at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:365) [shiro-web-1.2.2.jar:1.2.2]
        at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90) [shiro-core-1.2.2.jar:1.2.2]
        at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83) [shiro-core-1.2.2.jar:1.2.2]
        at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:383) [shiro-core-1.2.2.jar:1.2.2]
        at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:362) [shiro-web-1.2.2.jar:1.2.2]
        at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:125) [shiro-web-1.2.2.jar:1.2.2]
        at io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:56) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:132) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:85) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at org.wildfly.extension.undertow.security.SecurityContextAssociationHandler.handleRequest(SecurityContextAssociationHandler.java:78)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:113) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.security.handlers.AuthenticationCallHandler.handleRequest(AuthenticationCallHandler.java:52) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:45) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:61) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.security.CachedAuthenticatedSessionHandler.handleRequest(CachedAuthenticatedSessionHandler.java:70) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.security.handlers.SecurityInitialHandler.handleRequest(SecurityInitialHandler.java:76) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:61)
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:25) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:240) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:227) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler.access$000(ServletInitialHandler.java:73) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:146) [undertow-servlet-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.Connectors.executeRootHandler(Connectors.java:168) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:687) [undertow-core-1.0.0.Final.jar:1.0.0.Final]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_45]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_45]
        at java.lang.Thread.run(Thread.java:744) [rt.jar:1.7.0_45]
Caused by: javax.el.PropertyNotFoundException: The class 'at.co.xss.Type2' does not have the property 'type1OnlyMethod'.
        at javax.el.BeanELResolver.getBeanProperty(BeanELResolver.java:730) [javax.el-3.0.0.jar:3.0.0]
        at javax.el.BeanELResolver.getValue(BeanELResolver.java:351) [javax.el-3.0.0.jar:3.0.0]
        at com.sun.faces.el.DemuxCompositeELResolver._getValue(DemuxCompositeELResolver.java:176) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.faces.el.DemuxCompositeELResolver.getValue(DemuxCompositeELResolver.java:203) [jsf-impl-2.2.5-jbossorg-3.jar:]
        at com.sun.el.parser.AstValue.getValue(AstValue.java:140) [javax.el-3.0.0.jar:3.0.0]
        at com.sun.el.parser.AstValue.getValue(AstValue.java:204) [javax.el-3.0.0.jar:3.0.0]
        at com.sun.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:226) [javax.el-3.0.0.jar:3.0.0]
        at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
        at org.jboss.weld.el.WeldValueExpression.getValue(WeldValueExpression.java:50) [weld-core-impl-2.1.2.Final.jar:2014-01-09 09:23]
        at com.sun.faces.facelets.el.TagValueExpression.getValue(TagValueExpression.java:109) [jsf-impl-2.2.5-jbossorg-3.jar:]
        ... 66 more

It seems that in the render-response phase the nested ui:repeat is "executed" for the currently deleted Type2 object.

If I remove the second (nested) ui:repeat and add some plain h:outputText to access the property which is only available in Type1, everything works again without exception when I add or remove elements:

<h:form id="dummyForm">
  <ui:repeat value="#{dummyBean.objects}" var="_obj" >
    <!-- ... -->
    <h:panelGroup rendered="#{_obj.type eq '1'}">
      <h:outputText value="#{_obj.type1OnlyMethod.size()}" />
    </h:panelGroup>
    <!-- ... -->
</h:form>

Does anyone have any idea on this topic?

(Running on JEE7 application server (Wildfly 8.0.0.Final))

回答1:

This is caused by a bug in state management of Mojarra's <ui:repeat> which is fixed as per issue 3215 as reported by my fellow Arjan Tijms. We also faced this problem when iterating over different Block instances at zeef.com (LinkBlock, ImageBlock, TextBlock and FeedBlock). The fix is available in Mojarra 2.2.7 and for JSF 2.0/2.1 backported to Mojarra 2.1.29 as per issue 3221. So upgrading to at least that version (or just the latest available as per Mojarra homepage) should do it.

Otherwise, your best bet is to replace <ui:repeat> by <c:forEach>.



回答2:

In my case I didn't had the option to upgrade Mojarra's version and to avoid c:forEach (that causes many side-effects when used with ui optionally rendered components) I replaced ui:repeat with a p:dataList and it worked. You'll have to do some CSS styling to hide the bullets but I think it's worth the price. I hope it helps someone ;)