1 2 Previous Next 18 Replies Latest reply on Mar 13, 2009 3:56 PM by markstrecker

    Using EL Functions in an AJAX request

    imkookoo

      I'm encountering an issue with using the "rich:clientId" EL function in my application. I wrote a small test and was able to replicate the issue:

      <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
      <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
      <%@ taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
      <%@ taglib uri="http://richfaces.org/rich" prefix="rich" %>
      
      <f:view>
      
       <h:form id="testForm">
      
       <h:outputText value="#{rich:clientId('testTable')}"/>
      
       <h:panelGroup id="testTable" rendered="#{UserPreferencePage.testVisible}">
       <h:outputText value="#{rich:clientId('testTable')}"/>
       </h:panelGroup>
      
       <a4j:commandLink value="Test Link" action="#{UserPreferencePage.showTest}" reRender="testTable"/>
      
       </h:form>
      
      </f:view>
      
      


      The page above basically is supposed to show the client ID of the testTable component and an a4j command link to display another panel that also has the same client ID text.

      When the page above is loaded, it displays "testForm:testTable" just fine, but then you click on the "Test Link" link, you get an exception thrown:


      org.apache.jasper.el.JspELException: /wally/Test.jsp(13,4) '#{rich:clientId('testTable')}' Function 'rich:clientId' not found
      org.apache.jasper.el.JspValueExpression.getValue(JspValueExpression.java:107)
      javax.faces.component.UIOutput.getValue(UIOutput.java:184)
      com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:201)
      com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.getCurrentValue(HtmlBasicRenderer.java:284)
      com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeEnd(HtmlBasicRenderer.java:154)
      javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:861)
      com.sun.faces.renderkit.html_basic.HtmlBasicRenderer.encodeRecursive(HtmlBasicRenderer.java:242)
      com.sun.faces.renderkit.html_basic.GroupRenderer.encodeChildren(GroupRenderer.java:106)
      javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:837)
      org.ajax4jsf.renderkit.RendererBase.renderChild(RendererBase.java:282)
      org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:124)
      org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxChildren(AjaxChildrenRenderer.java:67)
      org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:115)
      org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxChildren(AjaxChildrenRenderer.java:67)
      org.ajax4jsf.renderkit.AjaxChildrenRenderer.encodeAjaxComponent(AjaxChildrenRenderer.java:115)
      org.ajax4jsf.renderkit.AjaxContainerRenderer.encodeAjax(AjaxContainerRenderer.java:123)
      org.ajax4jsf.component.AjaxViewRoot.encodeAjax(AjaxViewRoot.java:677)
      org.ajax4jsf.component.AjaxViewRoot.encodeChildren(AjaxViewRoot.java:548)
      javax.faces.component.UIComponent.encodeAll(UIComponent.java:936)
      com.sun.faces.application.ViewHandlerImpl.doRenderView(ViewHandlerImpl.java:271)
      com.sun.faces.application.ViewHandlerImpl.renderView(ViewHandlerImpl.java:202)
      org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:108)
      org.ajax4jsf.application.AjaxViewHandler.renderView(AjaxViewHandler.java:196)
      com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:109)
      com.sun.faces.lifecycle.Phase.doPhase(Phase.java:100)
      com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
      javax.faces.webapp.FacesServlet.service(FacesServlet.java:266)
      org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:177)
      org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:267)
      org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:380)
      org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:507)
      org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)



      Is there something I'm doing wrong, or is this a bug?

      Regards.

        • 1. Re: Using EL Functions in an AJAX request
          imkookoo

          Also what's interesting is if I remove the use of the clientId function inside of the panelGroup, as follows:

          <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
          <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
          <%@ taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
          <%@ taglib uri="http://richfaces.org/rich" prefix="rich" %>
          
          <f:view>
          
           <h:form>
          
           <h:outputText value="#{rich:clientId('testTable')}"/>
          
           <h:panelGroup id="testTable" rendered="#{UserPreferencePage.testVisible}">
           <h:outputText value=""/>
           </h:panelGroup>
          
           <a4j:commandLink value="akjdf" action="#{UserPreferencePage.showTest}" reRender="testTable"/>
          
           </h:form>
          
          </f:view>
          



          ... I get a different exception thrown:

          java.lang.NullPointerException
           org.apache.el.lang.FunctionMapperImpl$Function.writeExternal(FunctionMapperImpl.java:123)
           java.io.ObjectOutputStream.writeExternalData(ObjectOutputStream.java:1310)
           java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1288)
           java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1079)
           java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:302)
           java.util.HashMap.writeObject(HashMap.java:1039)
           sun.reflect.GeneratedMethodAccessor168.invoke(Unknown Source)
           sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
           java.lang.reflect.Method.invoke(Method.java:585)
           java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:917)
           java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1339)
           java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1290)
           java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1079)
           java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:302)
           org.apache.el.lang.FunctionMapperImpl.writeExternal(FunctionMapperImpl.java:74)
          
          


          So it looks like it's still trying to evaluate the clientId EL function... This has been preventing me from using rich:clientId function in any page that I use the a4j ajax control.

          • 2. Re: Using EL Functions in an AJAX request
            nbelaevski

            Hi,

            What is your RichFaces version? Functions are not available for 3.1.x versions. Please provide details about Tomcat version also.

            • 3. Re: Using EL Functions in an AJAX request
              imkookoo

               

              "nbelaevski" wrote:
              Hi,

              What is your RichFaces version? Functions are not available for 3.1.x versions. Please provide details about Tomcat version also.


              Hello,

              Thank you for your response. I am using the latest Richfaces version: 3.2.2, and deploying my application to a JBOSS App Server (v4.2.3).

              The function (rich:clientId) is running fine when the page loads normally, but whenever the user clicks on an AJAX button or link, the page fails whether or not that function is included in the reRender (as above, it gives me the first exception if it is part of the reRender, and it gives me the second exception when it's not part of the reRender).

              • 4. Re: Using EL Functions in an AJAX request
                stefan.mohr

                I believe it's a RichFaces no-no to perform a reRender on a control that also has the rendered attribute set.

                I've seen this alluded to in other posts but haven't read anything that explicitly explains what the rules are for this.

                • 5. Re: Using EL Functions in an AJAX request
                  stefan.mohr

                  Here's the thread I was thinking of:
                  http://www.jboss.com/index.html?module=bb&op=viewtopic&t=110311

                  Most notably:
                  ilya_shaikovsky:

                  You may not reRender components based on rendered attribute. Wrap it to something which is present in tree always (outputPanel with none layout) and then reRender wrapper.


                  SergeySmirnov:
                  Key rule - do not point with reRender to the id of the component that has 'rendered' attribute. You did it twice. To minimize the changes you can each of the rerendered component with a4j:outputPanel layout="none"


                  • 6. Re: Using EL Functions in an AJAX request
                    imkookoo

                     

                    "stefan.mohr" wrote:
                    Here's the thread I was thinking of:
                    http://www.jboss.com/index.html?module=bb&op=viewtopic&t=110311

                    Most notably:
                    ilya_shaikovsky:
                    You may not reRender components based on rendered attribute. Wrap it to something which is present in tree always (outputPanel with none layout) and then reRender wrapper.


                    SergeySmirnov:
                    Key rule - do not point with reRender to the id of the component that has 'rendered' attribute. You did it twice. To minimize the changes you can each of the rerendered component with a4j:outputPanel layout="none"


                    Thank you; I was not aware of that.

                    However, I am still encountering the same issue. I have modified the above test code to the following:

                    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
                    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
                    <%@ taglib uri="http://richfaces.org/a4j" prefix="a4j"%>
                    <%@ taglib uri="http://richfaces.org/rich" prefix="rich" %>
                    
                    <f:view>
                    
                     <h:form>
                    
                     <h:outputText value="#{rich:clientId('testTable')}"/>
                    
                     <a4j:region>
                     <h:panelGroup id="testTable">
                     <h:panelGroup rendered="#{UserPreferencePage.testVisible}">
                     <h:outputText value="#{rich:clientId('testTable')}"/>
                     </h:panelGroup>
                     </h:panelGroup>
                    
                     <a4j:commandLink value="akjdf" action="#{UserPreferencePage.showTest}" reRender="testTable"/>
                     </a4j:region>
                    
                     </h:form>
                    
                    </f:view>
                    


                    ... and am still getting the same exception.

                    • 7. Re: Using EL Functions in an AJAX request
                      imkookoo

                      Sorry for the multiple posts; I wish I could edit my posts on here.

                      I put in the "<a4j:region>" tags just to test, but the exception occurs both with and without that tag.

                      • 8. Re: Using EL Functions in an AJAX request
                        imkookoo

                        I think I found the issue: The exception is thrown whenever the #{rich:clientId} function -- or possibly any EL function for that matter -- is used in a component that is either not rendered, or not part of the AJAX reRender (ONLY during an AJAX submit like when you click on a a4j:commandLink or commandButton)

                        For example, this will fail when you click the "Rerender testTable panelGroup" link (notice the clientId function is called in a panelGroup that is never rendered):

                        <f:view>
                        
                         <h:form>
                         <h:panelGroup id="testTable">
                         <h:panelGroup rendered="false">
                         <h:outputText value="#{rich:clientId('testTable')}"/>
                         </h:panelGroup>
                         </h:panelGroup>
                         <a4j:commandLink value="Rerender testTable panelGroup" action="#{SomeBean.doNothing}" reRender="testTable"/>
                        
                         </h:form>
                        
                        </f:view>
                        


                        .. and even though the following will display the correct client ID when you first load the page, this will also fail when clicking the same link ( Notice that the clientId function is being called OUTSIDE of anything being rerendered):

                        <f:view>
                        
                         <h:form>
                         <h:outputText value="#{rich:clientId('testTable')}"/>
                        
                         <h:panelGroup id="testTable">
                         <h:panelGroup rendered="false">
                         </h:panelGroup>
                         </h:panelGroup>
                         <a4j:commandLink value="Rerender testTable panelGroup" action="#{UserPreferencePage.showTest}" reRender="testTable"/>
                        
                         </h:form>
                        
                        </f:view>
                        


                        ... but this will run just fine (notice that the clientId function is being called WITHIN the reRender and it is rendered):

                        <f:view>
                        
                         <h:form id="testForm">
                         <h:panelGroup id="testTable">
                         <h:outputText value="#{rich:clientId('testTable')}"/>
                         </h:panelGroup>
                         <a4j:commandLink value="Rerender testTable panelGroup" action="#{UserPreferencePage.showTest}" reRender="testTable"/>
                         </h:form>
                        
                        </f:view>
                        


                        • 9. Re: Using EL Functions in an AJAX request
                          nbelaevski

                          Here is the page I've used for testing:

                          <?xml version="1.0" encoding="UTF-8"?>
                          
                          <jsp:root version="2.1" xmlns:jsp="http://java.sun.com/JSP/Page"
                           xmlns:c="http://java.sun.com/jsp/jstl/core"
                           xmlns:f="http://java.sun.com/jsf/core"
                           xmlns:h="http://java.sun.com/jsf/html"
                           xmlns:rich="http://richfaces.org/rich"
                           xmlns:a4j="http://richfaces.org/a4j">
                          
                           <jsp:directive.page contentType="text/html;charset=UTF-8"
                           pageEncoding="UTF-8" />
                           <jsp:output omit-xml-declaration="no" doctype-root-element="html"
                           doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
                           doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" />
                          
                           <f:view>
                           <html xmlns="http://www.w3.org/1999/xhtml">
                           <body>
                           <h:form>
                           <h:panelGroup id="testTable">
                           <h:panelGroup rendered="false">
                           <h:outputText value="#{rich:clientId('testTable')}" />
                           </h:panelGroup>
                           </h:panelGroup>
                           <a4j:commandLink value="Rerender testTable panelGroup"
                           reRender="testTable" />
                          
                           </h:form>
                           </body>
                           </html>
                           </f:view>
                          </jsp:root>


                          works fine with JBoss 4.2.3 - clicking the link updates empty testTable span.

                          My guess is that there are some conflicting libraries bundled with your application. What files do you have in WEB-INF/lib?

                          • 10. Re: Using EL Functions in an AJAX request
                            imkookoo

                            Thanks for the response (and sorry for the delay in responding; I haven't had a chance to work on this until today).

                            After much library analyzing and configuration altering, I finally pinpointed the issue.

                            In my WEB.XML configuration, I have STATE_SAVING_METHOD='client'. When STATE_SAVING_METHOD = 'server', the code above works fine. Otherwise, if it is "client", it will give you the error I was getting.

                            Is there a workaround for this? Cause I really would like to use "client" in order to have back-button compatibility. Thank you,

                            • 11. Re: Using EL Functions in an AJAX request
                              imkookoo

                              Looking through the forums, I think I found another thread with the exact same issue I am having, but the thread does not have a resolution as well:

                              http://jboss.com/index.html?module=bb&op=viewtopic&t=92995

                              • 12. Re: Using EL Functions in an AJAX request
                                nbelaevski

                                Ok, now I'm able to reproduce the NPE issue. It is caused by bug in JBoss server, see: http://fisheye.jboss.org/browse/JBossWeb/trunk/java/org/apache/el/lang/FunctionMapperImpl.java?r=170 line 123. For your case this.m is null on serialization because method has not been called since FunctionMapper has been deserialized. The problem has been fixed in later revisions: http://fisheye.jboss.org/browse/JBossWeb/trunk/java/org/apache/el/lang/FunctionMapperImpl.java?r=582 see line 123 again.

                                As a workaround I can recommend to call rich:clientId function every request, e.g. wrap it inside <a4j:outputPanel ajaxRendered="true" style="display: none">

                                • 13. Re: Using EL Functions in an AJAX request
                                  imkookoo

                                  I switched back my state saving method to "Client" and tried the workaround you suggested:

                                  <?xml version="1.0" encoding="UTF-8"?>
                                  
                                  <jsp:root version="2.1" xmlns:jsp="http://java.sun.com/JSP/Page"
                                   xmlns:c="http://java.sun.com/jsp/jstl/core"
                                   xmlns:f="http://java.sun.com/jsf/core"
                                   xmlns:h="http://java.sun.com/jsf/html"
                                   xmlns:rich="http://richfaces.org/rich"
                                   xmlns:a4j="http://richfaces.org/a4j">
                                  
                                   <jsp:directive.page contentType="text/html;charset=UTF-8"
                                   pageEncoding="UTF-8" />
                                   <jsp:output omit-xml-declaration="no" doctype-root-element="html"
                                   doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
                                   doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" />
                                  
                                   <f:view>
                                   <html xmlns="http://www.w3.org/1999/xhtml">
                                   <body>
                                  
                                   <a4j:outputPanel id="forceELFunctionSerialization" ajaxRendered="true" style="display: none">
                                   <h:outputText value="#{rich:clientId('testTable')}"></h:outputText>
                                   </a4j:outputPanel>
                                  
                                   <h:form>
                                   <h:panelGroup id="testTable">
                                   <h:panelGroup rendered="true">
                                   <h:outputText value="#{rich:clientId('testTable')}" />
                                   </h:panelGroup>
                                   </h:panelGroup>
                                   <a4j:commandLink value="Rerender testTable panelGroup"
                                   reRender="testTable" />
                                  
                                   </h:form>
                                   </body>
                                   </html>
                                   </f:view>
                                  </jsp:root>
                                  


                                  .. but now I get a function not found error when I click on the link. The same code is ok when I switch back to "server" mode.


                                  org.apache.jasper.el.JspELException: /wally/Test.jspx(21,73) '#{rich:clientId('testTable')}' Function 'rich:clientId' not found
                                  org.apache.jasper.el.JspValueExpression.getValue(JspValueExpression.java:107)
                                  javax.faces.component.UIOutput.getValue(UIOutput.java:184)
                                  com.sun.faces.renderkit.html_basic.HtmlBasicInputRenderer.getValue(HtmlBasicInputRenderer.java:201)





                                  • 14. Re: Using EL Functions in an AJAX request
                                    imkookoo

                                    Ok, I got it. My solution was to combine the new EL-API code with my existing the jbossweb 4.2.3 code. It works fine now.

                                    Thanks for all your help.

                                    1 2 Previous Next