2 Replies Latest reply on Mar 3, 2008 11:46 AM by Rajesh Advani

    Facelets - Accessing local variables via EL in custom tag handler

    Rajesh Advani Newbie

      Hi, this is a cross post from the facelets users and dev lists. I didn't get much of a response there, and I'm beginning to feel this might be a bug in com/sun/facelets/impl/DefaultFaceletContext.java, though I'm not sure yet.


      Here's the description from the original post:


      I'm using Facelets 1.1.13 with Seam 1.2.1 under WebLogic 10, and have written a custom tag handler, to implement a tag library in my application.


      Here's what I do:


           public final class MyTagHandler extends TagHandler {
           
               private final TagAttribute value;
               // Some more attributes
            
               public MyTagHandler(TagConfig config) {
                   super(config);
                   this.value = this.getAttribute("value");
               }
           
               public void apply(FaceletContext ctx, UIComponent parent)
                       throws IOException, FacesException, FaceletException, ELException {
                  // Some processing goes here.
                  Object value = getValue(ctx);
                  // More processing
                 return;
               }
           
               public Object getValue(FaceletContext ctx) {
                   if (this.value != null) {
                       return this.value.getObject(ctx);
                   } else {
                       return null;
                   }
               }
           .
           .
           .
           }
      




      This is how I set it up in the taglib.xml:


           <facelet-taglib>
            <namespace>http://mydomain.net/tags</namespace>
            <tag>
             <tag-name>mytag</tag-name>
             <handler-class>net.mydomain.MyTagHandler</handler-class>
            </tag>
           </facelet-taglib>
      



      This is how the tag is used in the XHTML files:



           <myprefix:mytag value="somevalue">
      




      • If somevalue is a literal, this works fine.

      • If somevalue is an EL expression of the form #{customer.name} (where the bean customer has a property name)

      • a. If customer is a component defined in faces-config.xml, then it works fine

      • b. If customer is outjected (using the Out Seam annotation) to - say - the session scope, then this works fine

      • c. If customers (plural), is a component which has multiple customers, and I use a tag like c:forEach or h:dataTable to loop over each customer, like so:



                <c:forEach items="#{customers}" var="customer">
                  <myprefix:mytag value="#{customer.name}"/>
                </c:forEach>
      



           then getValue(ctx) as written above in the apply method, evaluates to null.


      If I use this.value.getValue(ctx); instead of this.value.getObject(ctx);, it's the same thing.
      If I use code like this.value.getValueExpression(ctx,
      String.class).getValue(ctx)
      instead, I get an empty string.
      If I use code like this.value.getValueExpression(ctx,
      String.class).getType(ctx)
      instead, I get the following exception:



      Feb 20, 2008 8:06:37 PM com.sun.facelets.FaceletViewHandler
      handleRenderException
      SEVERE: Error Rendering View\[/mypage.xhtml\]
      javax.el.PropertyNotFoundException: /mypage.xhtml @97,66
      value="${customer.name}": Target Unreachable, identifier 'customer'
      resolved to null
              at
      com.sun.facelets.el.TagValueExpression.getType(TagValueExpression.java:6
      2)
              at
      net.mydomain.MyTagHandler.getValue(DisplayStringParamTagHandler.java:122
      )
              at
      net.mydomain.MyTagHandler.apply(DynamicDisplayStringHandler.java:81)
              at
      com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandl
      er.java:47)
              at
      com.sun.facelets.tag.jsf.ComponentHandler.applyNextHandler(ComponentHand
      ler.java:314)
              at
      com.sun.facelets.tag.jsf.ComponentHandler.apply(ComponentHandler.java:16
      9)
              at
      com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandl
      er.java:47)
              at
      com.sun.facelets.tag.jsf.ComponentHandler.applyNextHandler(ComponentHand
      ler.java:314)
              at
      com.sun.facelets.tag.jsf.ComponentHandler.apply(ComponentHandler.java:16
      9)
              at
      com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandl
      er.java:47)
              at
      com.sun.facelets.tag.jsf.core.ViewHandler.apply(ViewHandler.java:109)
              at
      com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandl
      er.java:47)
              at
      com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:4
      9)
              at
      com.sun.facelets.tag.CompositeFaceletHandler.apply(CompositeFaceletHandl
      er.java:47)
              at
      com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25)
              at
      com.sun.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:95)
              at
      com.sun.facelets.FaceletViewHandler.buildView(FaceletViewHandler.java:50
      3)
              at
      com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:5
      46)
              at
      org.ajax4jsf.framework.ViewHandlerWrapper.renderView(ViewHandlerWrapper.
      java:108)
              at
      org.ajax4jsf.framework.ajax.AjaxViewHandler.renderView(AjaxViewHandler.j
      ava:229)
              at
      org.apache.myfaces.lifecycle.RenderResponseExecutor.execute(RenderRespon
      seExecutor.java:41)
              at
      org.apache.myfaces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:132
      )
              at
      javax.faces.webapp.FacesServlet.service(FacesServlet.java:140)
              at
      weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(St
      ubSecurityHelper.java:226)
              at
      weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityH
      elper.java:124)
              at
      weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:2
      83)
              at
      weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
              at
      weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:
      42)
              at
      org.jboss.seam.web.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:6
      3)
              at
      org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45)
              at
      org.jboss.seam.web.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:4
      9)
              at
      org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:57)
      
      



      Note that code like -


                <c:forEach items="#{customers}" var="customer">
                  #{customer.name}
                </c:forEach>
      



      - works just fine.


      I'm guessing that maybe the ELContext that the customer variable is stored to, is different than the one my tag tries to use. What I can't understand is Why?, and How do I fix it?


      Any insights into this would be highly appreciated.


      Regards,


      Rajesh