webtier@glassfish.java.net

Re: [webtier] JSF2: MethodExpression attribute doesn't get set

From: Ryan Lubke <Ryan.Lubke_at_Sun.COM>
Date: Mon, 27 Jul 2009 09:40:43 -0700

On 7/23/09 7:38 PM, webtier_at_javadesktop.org wrote:
> I'm converting a couple of components and their demo programs from 1.2 to 2.0. The components have an attribute whose value is a MethodExpression:
> <ah:selectDiagram ... configuration="#{handler.configure}" ... />
>
> In JSF2 I'm finding that the value gets set as a ValueExpression in the attributes map rather than setting the component's configuration property as a MethodExpression.
>
> Workarounds would be to extract the String value from the ValueExpression, or define a new attribute that takes a String value "handler.configure" (as I did) and build a MethodExpression from it. But surely this wasn't what was intended?
>
Unfortunately, the spec hasn't exposed certain Facelet internals yes, so
doing this will require a little more code than should be necessary.
I'll be logging an issue against the spec shortly.

So, to have custom MethodExpression enabled attributes, you will need to
provide a custom tag handler for your selectDiagram
component.

I hope the formatting comes across ok....

|public final class SelectDiagramHandler extends ComponentHandler {

     private static final MethodRule CONFIG_RULE =
         new MethodRule("configuration", Void.class, new Class[] { ActionEvent.class });

     public SelectDiagramHandler(ComponentConfig config) {
         super( config );
     }

     protected MetaRuleset createMetaRuleset(Class type) {
         return super.createMetaRuleset(type).addRule(CONFIG_RULE);
     }


     // ------------------------------------------- Nested Classes

     /**
      * This can re-used across custom handlers, and is in fact,
      * pretty close to the implementation specific utility class
      * for this use case. The spec should have exposed this.
      */
     private static final class MethodRule extends Metarule {

         |
| public MethodRule(String methodName,
                            Class<?> returnType,
                            Class<?>[] arguments) {

             this.methodName = methodName;
             this.returnType = returnType;
             this.arguments = arguments;

         }||

         public Metadata applyRule(String name,
                                   TagAttribute attribute,
                                   MetadataTarget meta) {
             if (!name.equals(methodName)) {
                 return;
             }
             // obtain the method to which we pass the
             // MethodExpression instance to
             Method writeMethod = meta.getWriteMethod();
             if (writeMethod != null) {
                return new MethodExpressionMetadata(
             }
         }

         // ------------------------------- Nested Classes

         |
| private static final class MethodExpressionMetadata extends Metadata {

             private final Method writeMethod;
             private final TagAttribute attribute;
|| private Class<?> returnType;|
| private Class<?>[] arguments;

             public MethodExpressionMetadata(Method writeMethod,
                                             TagAttribute attribute,
                                             Class<?> returnType,
                                             Class<?>[] arguments) {

                this.writeMethod = writeMethod;
                 this.attribute = attribute;
                 this.returnType = returnType;
                 this.arguments = arguments;

             }

             public void applyMetadata(FaceletContext ctx, Object instance) {

                 MethodExpression expr = attribute.getMethodExpression(ctx,
                                                                       returnType,
                                                                       arguments);
                 // pass the method expression to the component
                 try {
                     writeMethod.invoke(instance, expr);
                 } catch (InvocationTargetException e) {
                     throw new TagAttributeException(attribute, e.getCause());
                 } catch (Exception e) {
                     throw new TagAttributeException(attribute, e);
                 }
             }
         } // END MethodExpressionMetadata||

     } // END SelectDiagramHandlerRule||

  } // END SelectDiagramHandler|


Then register your custom tag handler in a facelet-taglibrary:

<facelet-taglib xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facelettaglibary_2_0.xsd"
               version="2.0">
<namespace>YOUR_NAMESPACE_HERE</namespace>
<tag>
<tag>
<tag-name>selectDiagram</tag-name>
<component>
<component-type>your_selectDiagram_component_type</component-type>
<handler-class>fully_qualified_handler_class_from_above</handler-class>
</component>
</tag>
</facelet-taglib>


> (using Glassfish 2.1 with the JSF2 libs, if that makes a difference).
> [Message sent by forum member 'judys' (judys)]
>
> http://forums.java.net/jive/thread.jspa?messageID=357350
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: webtier-unsubscribe_at_glassfish.dev.java.net
> For additional commands, e-mail: webtier-help_at_glassfish.dev.java.net
>
>