ICEfaces
  1. ICEfaces
  2. ICE-8180

ace:ajax - PropertyNotFoundException thrown

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 3.1.0.BETA1
    • Fix Version/s: 3.1.0.RC1, 3.1
    • Component/s: ACE-Components
    • Labels:
      None
    • Environment:
      ICEfaces 3.1.0 BETA1
    • Assignee Priority:
      P2
    • Workaround Exists:
      Yes
    • Workaround Description:
      Hide
      Defining the param outside the ui:include works around this issue. Eg.

              <h:form id="iceForm">
                  
                  <ui:include src="table.xhtml"/>
                  <ui:param name="backingBean" value="#{testBean}"/>

              </h:form>

      Where the param is also identically defined in table.xhtml.
      Show
      Defining the param outside the ui:include works around this issue. Eg.         <h:form id="iceForm">                          <ui:include src="table.xhtml"/>             <ui:param name="backingBean" value="#{testBean}"/>         </h:form> Where the param is also identically defined in table.xhtml.

      Description

      A PropertyNotFoundException is thrown when setting the listener attribute thats managed bean is set via a ui:param tag. The ace:ajax tag is set for a row select event for an ace:dataTable. The table code is being included in a main page via a ui:include. The included table page sets a ui:param name="'backingBean" thats value is the managed bean.

      The ace:dataTable uses the same param and works correctly. When a row is selected the ace:ajax tag fires its listener and throws the following error:

      Caused by: javax.el.PropertyNotFoundException: Target Unreachable, identifier 'backingBean' resolved to null
      at org.apache.el.parser.AstValue.getTarget(AstValue.java:98)
      at org.apache.el.parser.AstValue.invoke(AstValue.java:244)
      at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:278)
      at org.icefaces.ace.component.ajax.AjaxBehavior.broadcast(AjaxBehavior.java:170)
      at javax.faces.component.UIComponentBase.broadcast(UIComponentBase.java:760)
      at javax.faces.component.UIData.broadcast(UIData.java:1071)
      at org.icefaces.ace.component.datatable.DataTable.broadcast(DataTable.java:220)
      at javax.faces.component.UIData.broadcast(UIData.java:1093)
      at org.icefaces.ace.component.datatable.DataTable.broadcast(DataTable.java:220)
      at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)
      at javax.faces.component.UIViewRoot.processApplication(UIViewRoot.java:1259)
      at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:81)

        Issue Links

          Activity

          Hide
          Arran Mccullough added a comment -

          Attached test case that shows issue.

          Steps:

          • Load welcomeICEfaces.jsf
          • Select the row in the table, error is thrown.
          Show
          Arran Mccullough added a comment - Attached test case that shows issue. Steps: Load welcomeICEfaces.jsf Select the row in the table, error is thrown.
          Hide
          Nils Lundquist added a comment -

          I've discovered a workaround. I was also unable to reproduce this issue in the showcase.

          I'm attempting to distill this issue into a pure JSF case as I believe the failure here is a scoping issue between ui:include and EL evaluation.

          Show
          Nils Lundquist added a comment - I've discovered a workaround. I was also unable to reproduce this issue in the showcase. I'm attempting to distill this issue into a pure JSF case as I believe the failure here is a scoping issue between ui:include and EL evaluation.
          Hide
          Nils Lundquist added a comment -

          Converting the test case to use h:dataTable and h:commandButton with a 'backingBean' method expression actionListener causes the same error.

          This is a framework JSF deficiency or bug depending on how you think EL scope in ui:includes should be handled.

          Show
          Nils Lundquist added a comment - Converting the test case to use h:dataTable and h:commandButton with a 'backingBean' method expression actionListener causes the same error. This is a framework JSF deficiency or bug depending on how you think EL scope in ui:includes should be handled.
          Hide
          Nils Lundquist added a comment -

          Adding the ui:param to the global f:metadata region resolves this issue but with the same caveats as the existing workaround, that the parameter must be defined globally.

          Show
          Nils Lundquist added a comment - Adding the ui:param to the global f:metadata region resolves this issue but with the same caveats as the existing workaround, that the parameter must be defined globally.
          Hide
          Mark Collette added a comment -

          At first I thought it was a matter of syntax, so Arran tested using listener="#

          {backingBean[rowSelectListener]}

          " but that didn't work because I had confised rowSelectListener for another ui:param, but really is was the method name, so he tried listener="#

          {backingBean['rowSelectListener']}" but that didn't work either.

          We then tried an h:commandButton inside the dataTable with an actionListener using four syntaxes, to see if it was not working due to being inside a dataTable. But it worked.

          So then we tried an h:commandButton with ace:ajax and listener outside of the dataTable, to establish if it was just ace:ajax's listener not working.

          <h:commandButton value="Test Outside Action">
          <ace:ajax event="click" listener="#{testBean['rowSelectListener']}"/>
          </h:commandButton>

          The four syntaxes:
             listener="#{backingBean.rowSelectListener}"
             listener="#{backingBean['rowSelectListener']}

          "
             listener="#

          {testBean.rowSelectListener}

          "
             listener="#

          {testBean['rowSelectListener']}

          "

          The direct bean references worked, but not the indirect ones.

          I looked in the code and there's a bit where the exception is coming from, in AjaxBehavior.broadcast, where it first tries a no-arg method expression invocation, and then constructs a new one on the fly to take the argument. I distrusted the construction code, so changed it so that the AjaxBehaviorHandler would just wire up the one with an argument, and broadcast would just call it, and then we made that app take that argument, and it started working, with the indirect syntax.

          So, the technical hurdle will be to find a way of supporting no argument and the event argument on the ace:ajax listener, without doing the method expression creation that doesn't seem to work.

          Show
          Mark Collette added a comment - At first I thought it was a matter of syntax, so Arran tested using listener="# {backingBean[rowSelectListener]} " but that didn't work because I had confised rowSelectListener for another ui:param, but really is was the method name, so he tried listener="# {backingBean['rowSelectListener']}" but that didn't work either. We then tried an h:commandButton inside the dataTable with an actionListener using four syntaxes, to see if it was not working due to being inside a dataTable. But it worked. So then we tried an h:commandButton with ace:ajax and listener outside of the dataTable, to establish if it was just ace:ajax's listener not working. <h:commandButton value="Test Outside Action"> <ace:ajax event="click" listener="#{testBean['rowSelectListener']}"/> </h:commandButton> The four syntaxes:    listener="#{backingBean.rowSelectListener}"    listener="#{backingBean['rowSelectListener']} "    listener="# {testBean.rowSelectListener} "    listener="# {testBean['rowSelectListener']} " The direct bean references worked, but not the indirect ones. I looked in the code and there's a bit where the exception is coming from, in AjaxBehavior.broadcast, where it first tries a no-arg method expression invocation, and then constructs a new one on the fly to take the argument. I distrusted the construction code, so changed it so that the AjaxBehaviorHandler would just wire up the one with an argument, and broadcast would just call it, and then we made that app take that argument, and it started working, with the indirect syntax. So, the technical hurdle will be to find a way of supporting no argument and the event argument on the ace:ajax listener, without doing the method expression creation that doesn't seem to work.
          Hide
          Mark Collette added a comment -

          Investigation of the two types of MethodExpression objects, the original and the copy, showed that the original was a com.sun.faces.facelets.el.TagMethodExpression, and the copy was a org.apache.el.MethodExpressionImpl. There wasn't anything in TagMethodExpression to explain a difference of EL evaluation. But, searching though the Mojarra source code found that the entire MethodExpression construction chain was full of composite component handling code and retargeting code, mostly in com.sun.* classes. I investigated all throughout the chain, but there didn't seem to be a way to replicate the handling within AjaxBehavior.

          The next approach taken was to use our AjaxBehaviorHandler as a hook into the process where the listener TagAttribute is processed and eventually results in the TagMethodExpression being set into the listener property on AjaxBehavior. There seemed to be a very 1:1 mapping between the two, but eventually I untangled that MetaRule objects are used to create Metadata objects, which can do arbitrary tasks on the UIComponent, and that our MethodRule code contains both, and in altering it, I could create a 1:2 mapping between the one TagAttribute and two properties for the MethodExpressions, so that instead of trying to carbon copy the MethodExpression later, we could instead have two originals, one for the argument and one for the no-argument, and all the regular Facelets/JSF processing would happen on both, so they would both be setup for working with composite components.

          Now ace:ajax will try to invoke the bean method that takes the event, and if it can't find it, then it will fall back to invoking a no-argument version of that method.

          In theory, we could alter other components, or the generator, to allow for our other listeners to use this one or no argument signature, to allow for applications to be more POJO.

          trunk
          Subversion 29289

          Show
          Mark Collette added a comment - Investigation of the two types of MethodExpression objects, the original and the copy, showed that the original was a com.sun.faces.facelets.el.TagMethodExpression, and the copy was a org.apache.el.MethodExpressionImpl. There wasn't anything in TagMethodExpression to explain a difference of EL evaluation. But, searching though the Mojarra source code found that the entire MethodExpression construction chain was full of composite component handling code and retargeting code, mostly in com.sun.* classes. I investigated all throughout the chain, but there didn't seem to be a way to replicate the handling within AjaxBehavior. The next approach taken was to use our AjaxBehaviorHandler as a hook into the process where the listener TagAttribute is processed and eventually results in the TagMethodExpression being set into the listener property on AjaxBehavior. There seemed to be a very 1:1 mapping between the two, but eventually I untangled that MetaRule objects are used to create Metadata objects, which can do arbitrary tasks on the UIComponent, and that our MethodRule code contains both, and in altering it, I could create a 1:2 mapping between the one TagAttribute and two properties for the MethodExpressions, so that instead of trying to carbon copy the MethodExpression later, we could instead have two originals, one for the argument and one for the no-argument, and all the regular Facelets/JSF processing would happen on both, so they would both be setup for working with composite components. Now ace:ajax will try to invoke the bean method that takes the event, and if it can't find it, then it will fall back to invoking a no-argument version of that method. In theory, we could alter other components, or the generator, to allow for our other listeners to use this one or no argument signature, to allow for applications to be more POJO. trunk Subversion 29289
          Hide
          Mark Collette added a comment -

          The test application should be able to have javax.faces.event.AjaxBehaviorEvent or no argument to its row selection method.

          Show
          Mark Collette added a comment - The test application should be able to have javax.faces.event.AjaxBehaviorEvent or no argument to its row selection method.
          Hide
          Arran Mccullough added a comment -

          Issue is now seen again when a composite component is on the page. This is a similar situation as what is found in ICE-8221

          Show
          Arran Mccullough added a comment - Issue is now seen again when a composite component is on the page. This is a similar situation as what is found in ICE-8221
          Hide
          Arran Mccullough added a comment -

          Attached new test case that shows the latest issue with the composite component.

          Show
          Arran Mccullough added a comment - Attached new test case that shows the latest issue with the composite component.
          Hide
          Mark Collette added a comment - - edited

          This caused regressions, which were addressed in ICE-8223. But ultimately this type of solution was superseded by ICE-8258, since when the full application scenario from ICE-8221 was tested against, this solution was insufficient, and ICE-8258 was needed.

          Show
          Mark Collette added a comment - - edited This caused regressions, which were addressed in ICE-8223 . But ultimately this type of solution was superseded by ICE-8258 , since when the full application scenario from ICE-8221 was tested against, this solution was insufficient, and ICE-8258 was needed.

            People

            • Assignee:
              Mark Collette
              Reporter:
              Arran Mccullough
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: