dev@javaserverfaces.java.net

Seeking Review from Jim: (was: Re: Defining methods in the interface - some ideas)

From: Ed Burns <Ed.Burns_at_Sun.COM>
Date: Thu, 13 Nov 2008 13:32:31 -0800

There's context on this thread that ya'll don't have, but you can just
look it as a code review request.

Jim, here's the change-bundle I needed to do to implement your feature.

It's less ugly than it looks.

>>>>> On Thu, 13 Nov 2008 04:07:27 -0800, Ed Burns <ed.burns_at_sun.com> said:

>>>>> On Wed, 12 Nov 2008 15:42:40 -0800, Jim Driscoll
EB> <Jim.Driscoll_at_Sun.COM> said:

JD> Is perfectly understandable. One comment on that though - why have the
JD> separate method-expression-name attribute, when you can just use the
JD> currently ignored methodname within the method signature? i.e., instead
JD> say:

EB> Yes, that's a better idea. I'll do that.

Turns out I didn't need to do that, so I dropped it.

JD> Now, let's discuss how it's applied against the implementation section.

JD> I really, really don't like the idea that in order to understand the
JD> implementation section, you have to know to refer to the interface
JD> section, without any hints to do so.

Ok, I did this by special casing the TagAttribute.java. Here goes.
Jim, I also fixed the XHTML for switchlist and now it works!

I'm checking this in now, and we can make changes as necessary.
Automated tests still run successfully.

SECTION: Modified Files
----------------------------
M jsf-api/src/javax/faces/application/ViewHandler.java

- retargetMethodExpressions()

  * Update spec reference section for metadata

  * rename the "applyTo" to "targets" for consistency with other
    elements.

  * assertion about method signature

M jsf-ri/conf/share/composite.tld

* document "targets" attribute

M jsf-ri/src/com/sun/faces/facelets/tag/TagAttribute.java

- This special behavior is specified in section 10.2.4.3. Here's the text.

  For code that handles tag attributes on UIComponent XHTML elements
  special action must be taken regarding composite
  components. [P1_start_composite_component_method_expression]If the
  type of the attribute is a MethodExpression, the code that takes the
  value of the attribute and creates an actual MethodExpression instance
  around it must take the following special action. Inspect the value of
  the attribute. If the EL expression string starts with the
  compositeComponent implicit object, is followed by the special string
  ?attrs? (without the quotes), as specified in Section 5.6.2.2
  ?Composite Component Attributes ELResolver?, and is followed by a
  single remaining expression segment, let the value of that remaining
  expression segment be attrName. In this case, the runtime must
  guarantee that the actual MethodExpression instance that is created
  for the tag attribute have the following behavior in its invoke()
  method.
  
  Obtain a reference to the current composite component by calling
  UIComponent.getCurrentCompositeComponent().
  
  Look in the attribute of the component for a key under the value
  attrName.
  
  There must be a value and it must be of type MethodExpression. If
  either of these conditions are false allow the ensuing exception to be
  thrown.
  
  Call invoke() on the discovered MethodExpression, passing the
  arguments passed to our invoke()
  method.[P1_end_composite_component_method_expression]
  
  [P1_start_composite_component_retargeting]Once the composite component
  has been populated with children, the runtime must ensure that
  ViewHandler.retargetAttachedObjects() and then
  ViewHandler.retargetMethodExpressions() is called, passing the top
  level component.[P1_end_composite_component_retargeting] The actions
  taken in these methods set the stage for the tag attribute behavior
  and the special MethodExpression handling behavior described
  previously.

M jsf-ri/src/com/sun/faces/facelets/tag/composite/AttributeHandler.java

- This is what handles the <composite:attribute> element. It's
  specified in the TLDDocs.

M jsf-ri/src/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java

- special case the handling of MethodExpressions found it tag
  attributes. This is specified in section 10.2.4.3. Here's the text.

  Special handling is required for attributes declared on the composite
  component tag instance in the using
  page. [P1_start_composite_component_tag_attributes]The runtime must
  ensure that all such attributes are copied to the attributes map of
  the top level component instance in the following manner.
  
  Obtain a reference to the ExpressionFactory, for discussion called
  expressionFactory.
  
  Let the value of the attribute in the using page be value.
  
  if value is ?id? or ?binding? without the quotes, skip to the next
  attribute.
  
  If the value of the attribute starts with ?#{? (without the quotes)
  call expressionFactory.createValueExpression(elContext, value,
  Object.class)
  
  If the value of the attribute does not start with ?#{?, call
  expressionFactory.createValueExpression(value, Object.class)
  
  If there already is a key in the map for value, inspect the type of
  the value at that key. If the type is MethodExpression take no
  action. [P1_end_composite_component_tag_attributes]

M jsf-ri/src/com/sun/faces/application/view/MultiViewHandler.java

- Comply with the new definition of retargetMethodExpressions

M jsf-ri/src/com/sun/faces/util/Util.java

- Add getTypeFromString

M jsf-demo/ezcomp02/src/main/webapp/WEB-INF/composite-test.taglib.xml
M jsf-demo/ezcomp02/src/main/webapp/WEB-INF/web.xml
M jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml
M jsf-demo/ajax-switchlist/web/resources/switchlist/switchlist.xhtml

- Fix these to be compliant.

SECTION: Diffs
----------------------------
Index: jsf-api/src/javax/faces/application/ViewHandler.java
===================================================================
--- jsf-api/src/javax/faces/application/ViewHandler.java (revision 5806)
+++ jsf-api/src/javax/faces/application/ViewHandler.java (working copy)
 -493,7 +493,7 @@
 
     /**
      * <p class="changed_added_2_0">Leverage the component metadata
- * specified in section 4.3.2 for the purpose of re-targeting any
+ * specified in section 3.6.2.1 for the purpose of re-targeting any
      * method expressions from the top level component to the
      * appropriate inner component. For each attribute that is a
      * <code>MethodExpression</code> (as indicated by the presence of a
 -505,13 +505,20 @@
      *
      * <ul>
      *
- * <li><p>Get the value of the <em>applyTo</em> attribute. If
- * not found, log an error and continue to the next
- * attribute.</p></li>
+ * <li><p>Get the value of the <em>targets</em> attribute. If the
+ * value is a <code>ValueExpression</code> evaluate it. If there is
+ * no <em>targets</em> attribute, let the name of the metadata
+ * element be the evaluated value of the <em>targets
+ * attribute.</em></p></li>
+ *
+ * <li><p>Interpret <em>targets</em> as a comma separated list of ids. For
+ * each entry in the list:</p>
+ *
+ * <ul>
      *
      * <li><p>Find the inner component of the
      * <em>topLevelComponent</em> with the id equal to
- * <em>applyTo</em>. For discussion, this component is called
+ * the current list entry. For discussion, this component is called
      * <em>target</em>. If not found, log and error and continue to
      * the next attribute.</p></li>
      *
 -574,15 +581,17 @@
      * <em>target</em>, passing <em>attributeMethodExpression</em> wrapped in a
      * {_at_link javax.faces.event.MethodExpressionValueChangeListener}.</p></li>
      *
- * <li><p>Otherwise, look for a JavaBeans setter that matches
- * <em>name</em> and assume it takes a
- * <code>MethodExpression</code>, passing
- * <em>attributeMethodExpression</em> as that expression. If
- * such a setter does not exist, or does not take a
- * <code>MethodExpression</code>, log an error and continue to
- * the next attribute.</p></li>
- *
+ * <li><p>Otherwise, assume that the <code>MethodExpression</code>
+ * should be placed in the components attribute set. The runtme
+ * must create the <code>MethodExpression</code> instance based on
+ * the value of the "<code>method-signature</code>"
+ * attribute.</p></li>
+
      * </ul>
+ *
+ * </li>
+ *
+ * </ul>
      *
      * <p>An implementation is provided that will throw
      * <code>UnsupportedOperationException</code>. A Faces implementation
Index: jsf-ri/conf/share/composite.tld
===================================================================
--- jsf-ri/conf/share/composite.tld (revision 5806)
+++ jsf-ri/conf/share/composite.tld (working copy)
 -532,6 +532,39 @@
 
                 <![CDATA[
 <div class="changed_added_2_0">
+
+<p>If the this element has a <code>method-signature</code> attribute,
+the value of the <code>targets</code> attribute must be interpreted as a
+comma separated list of component ids of components within the
+<code>&lt;composite:implementation&gt;</code> section. Each entry in
+the list must be interpreted as the id of an inner component to which
+the <code>MethodExpression</code> from the <em>composite component
+tag</em> in the <em>using page</em> must be applied. If the this
+element has a <code>method-signature</code> attribute, but no
+<code>targets</code> attribute, the value of the <code>name</code>
+attribute is used as the single entry in the list.</p>
+
+</div>]]>
+
+ </description>
+ <name>
+ targets
+ </name>
+ <required>
+ true
+ </required>
+ <deferred-value>
+ <type>
+ java.lang.String
+ </type>
+ </deferred-value>
+ </attribute>
+
+ <attribute>
+ <description>
+
+ <![CDATA[
+<div class="changed_added_2_0">
 <p>If this attribute is not required, and a
                 value is not supplied by the page author, use this as
                 the default value.</p></div>]]>
Index: jsf-ri/src/com/sun/faces/facelets/tag/TagAttribute.java
===================================================================
--- jsf-ri/src/com/sun/faces/facelets/tag/TagAttribute.java (revision 5806)
+++ jsf-ri/src/com/sun/faces/facelets/tag/TagAttribute.java (working copy)
 -51,15 +51,20 @@
 
 package com.sun.faces.facelets.tag;
 
+import javax.el.ELContext;
 import javax.el.ELException;
 import javax.el.ExpressionFactory;
 import javax.el.MethodExpression;
+import javax.el.MethodInfo;
 import javax.el.ValueExpression;
 
 import javax.faces.webapp.pdl.facelets.FaceletContext;
 import com.sun.faces.facelets.el.ELText;
 import com.sun.faces.facelets.el.TagMethodExpression;
 import com.sun.faces.facelets.el.TagValueExpression;
+import javax.faces.component.StateHolder;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
 
 /**
  * Representation of a Tag's attribute in a Facelet File
 -173,15 +178,119 @@
      */
     public MethodExpression getMethodExpression(FaceletContext ctx, Class type,
             Class[] paramTypes) {
+ MethodExpression result = null;
+ final String specialPrefix = "#{compositeComponent.attrs.";
+ final int specialPrefixLen = specialPrefix.length();
+ int i;
         try {
             ExpressionFactory f = ctx.getExpressionFactory();
- return new TagMethodExpression(this, f.createMethodExpression(ctx,
- this.value, type, paramTypes));
+ // Determine if this is a composite component attribute lookup.
+ // If so, look for a MethodExpression under the attribute key
+ if (this.value.startsWith(specialPrefix)) {
+ // Make sure this is *only* an attribute lookup
+ if (specialPrefixLen < this.value.length() &&
+ -1 == this.value.indexOf(".", specialPrefixLen)) {
+ String attrName = this.value.substring(specialPrefixLen,
+ this.value.length() - 1);
+ result = new AttributeLookupMethodExpression(this.value, attrName);
+ }
+ }
+ if (null == result) {
+ result = new TagMethodExpression(this, f.createMethodExpression(ctx,
+ this.value, type, paramTypes));
+ }
         } catch (Exception e) {
             throw new TagAttributeException(this, e);
         }
+ return result;
     }
+
+ private static class AttributeLookupMethodExpression extends MethodExpression implements StateHolder {
 
+ private String attrName = null;
+ private String expressionString = null;
+ private boolean isTransient = false;
+
+ public AttributeLookupMethodExpression(String expressionString,
+ String attrName) {
+ if (null == expressionString || null == attrName) {
+ throw new NullPointerException("null MethodExpression");
+ }
+ this.expressionString = expressionString;
+ this.attrName = attrName;
+ }
+
+ public AttributeLookupMethodExpression() {}
+
+ public boolean isTransient() {
+ return isTransient;
+ }
+
+ public void setTransient(boolean isTransient) {
+ this.isTransient = isTransient;
+ }
+
+ public void restoreState(FacesContext context, Object stateObj) {
+ String [] state = (String []) stateObj;
+ this.attrName = state[0];
+ this.expressionString = state[1];
+ }
+
+ public Object saveState(FacesContext arg0) {
+ String [] state = new String[2];
+ state[0] = this.attrName;
+ state[1] = this.expressionString;
+ return state;
+ }
+
+ @Override
+ public MethodInfo getMethodInfo(ELContext arg0) {
+ return null;
+ }
+
+ @Override
+ public Object invoke(ELContext elContext, Object[] arg1) {
+ Object result = null;
+ FacesContext context = (FacesContext) elContext.getContext(FacesContext.class);
+ // NPE is ok here.
+ UIComponent composite = UIComponent.getCurrentCompositeComponent(context);
+ MethodExpression me = null;
+ me = (MethodExpression) composite.getAttributes().get(attrName);
+ result = me.invoke(elContext, arg1);
+ return result;
+ }
+
+ @Override
+ public String getExpressionString() {
+ return expressionString;
+ }
+
+ @Override
+ public boolean equals(Object otherObj) {
+ boolean result = false;
+ if (otherObj instanceof AttributeLookupMethodExpression) {
+ AttributeLookupMethodExpression other =
+ (AttributeLookupMethodExpression) otherObj;
+ result = this.expressionString.equals(other.expressionString);
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isLiteralText() {
+ boolean result = false;
+
+ result = (this.expressionString.startsWith("#{") &&
+ (this.expressionString.endsWith("}")));
+ return result;
+ }
+
+ @Override
+ public int hashCode() {
+ return this.expressionString.hashCode();
+ }
+ }
+
     /**
      * The resolved Namespace for this attribute
      *
Index: jsf-ri/src/com/sun/faces/facelets/tag/composite/AttributeHandler.java
===================================================================
--- jsf-ri/src/com/sun/faces/facelets/tag/composite/AttributeHandler.java (revision 5806)
+++ jsf-ri/src/com/sun/faces/facelets/tag/composite/AttributeHandler.java (working copy)
 -163,9 +163,9 @@
                 propertyDescriptor.setValue("method-signature", ve);
             }
         }
- if (null != (attr = this.getAttribute("applyTo"))) {
+ if (null != (attr = this.getAttribute("targets"))) {
             ve = attr.getValueExpression(ctx, String.class);
- propertyDescriptor.setValue("applyTo", ve);
+ propertyDescriptor.setValue("targets", ve);
         }
         
 
Index: jsf-ri/src/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java
===================================================================
--- jsf-ri/src/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java (revision 5806)
+++ jsf-ri/src/com/sun/faces/facelets/tag/jsf/CompositeComponentTagHandler.java (working copy)
 -79,6 +79,7 @@
 import com.sun.faces.facelets.tag.TagAttribute;
 import com.sun.faces.facelets.tag.TagAttributes;
 import com.sun.faces.util.RequestStateManager;
+import javax.el.MethodExpression;
 import javax.faces.application.ViewHandler;
 
 /**
 -110,7 +111,6 @@
                         expressionFactory = ctx.getFacesContext().getApplication().
                                 getExpressionFactory();
                     }
- // PENDING(edburns): deal with methodExpressions
                     if (value.startsWith("#{")) {
                         expression = expressionFactory.
                                 createValueExpression(ctx, value, Object.class);
 -118,7 +118,22 @@
                         expression = expressionFactory.
                                 createValueExpression(value, Object.class);
                     }
- compositeComponent.getAttributes().put(name, expression);
+ // PENDING: I don't think copyTagAttributesIntoComponentAttributes
+ // should be getting called
+ // on postback, yet it is. In lieu of a real fix, I'll
+ // make sure I'm not overwriting a MethodExpression with a
+ // ValueExpression.
+ Map<String, Object> map = compositeComponent.getAttributes();
+ boolean doPut = true;
+ if (map.containsKey(name)) {
+ Object curVal = map.get(name);
+ if (curVal instanceof MethodExpression) {
+ doPut = false;
+ }
+ }
+ if (doPut) {
+ map.put(name, expression);
+ }
                 }
             }
         }
Index: jsf-ri/src/com/sun/faces/application/view/MultiViewHandler.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/view/MultiViewHandler.java (revision 5806)
+++ jsf-ri/src/com/sun/faces/application/view/MultiViewHandler.java (working copy)
 -260,14 +260,14 @@
             return;
         }
         PropertyDescriptor attributes[] = componentBeanInfo.getPropertyDescriptors();
- String applyTo = null, strValue = null;
+ String targets = null, attrName = null, strValue = null,
+ methodSignature = null;
         UIComponent target = null;
         ExpressionFactory expressionFactory = null;
         ValueExpression valueExpression = null;
         MethodExpression toApply = null;
         Class expectedReturnType = null;
         Class expectedParameters[] = null;
- boolean logError = false;
 
         for (PropertyDescriptor cur : attributes) {
             // If the current attribute represents a ValueExpression
 -278,105 +278,179 @@
             }
             // If the current attribute representes a MethodExpression
             if (null != (valueExpression = (ValueExpression) cur.getValue("method-signature"))) {
- strValue = (String) valueExpression.getValue(context.getELContext());
- if (null != strValue) {
+ methodSignature = (String) valueExpression.getValue(context.getELContext());
+ if (null != methodSignature) {
                 
                     // This is the name of the attribute on the top level component,
                     // and on the inner component.
- logError = false;
- if (null != (valueExpression = (ValueExpression) cur.getValue("applyTo"))) {
- applyTo = (String) valueExpression.getValue(context.getELContext());
- if (null == applyTo) {
- logError = true;
- }
+ if (null != (valueExpression = (ValueExpression) cur.getValue("targets"))) {
+ targets = (String) valueExpression.getValue(context.getELContext());
                     }
                     
- if (logError) {
- // PENDING error message in page?
- logger.severe("Unable to retarget MethodExpression. " +
- "Please specify \"applyTo\" attribute on <composite:attribute />");
- continue;
+ if (null == targets) {
+ targets = cur.getName();
                     }
                     
- // This is the inner component to which the attribute should
- // be applied
- target = topLevelComponent.findComponent(applyTo);
- if (null == applyTo) {
+ if (null == targets || 0 == targets.length()) {
                         // PENDING error message in page?
- logger.severe("Unable to retarget MethodExpression. " +
- "Unable to find inner component with id " +
- applyTo + ".");
+ logger.severe("Unable to retarget MethodExpression: " +
+ methodSignature);
                         continue;
                     }
+
+
+ String[] targetIds = targets.split(",");
+
+ for (String curTarget : targetIds) {
+
+ // This is the inner component to which the attribute should
+ // be applied
+ target = topLevelComponent.findComponent(curTarget);
+ if (null == targets) {
+ // PENDING error message in page?
+ logger.severe("Unable to retarget MethodExpression. " +
+ "Unable to find inner component with id " +
+ targets + ".");
+ continue;
+ }
 
- strValue = cur.getName();
+ attrName = cur.getName();
 
- // Find the attribute on the top level component
- valueExpression = (ValueExpression) topLevelComponent.getAttributes().
- get(strValue);
- if (null == valueExpression) {
- // PENDING error message in page?
- logger.severe("Unable to find attribute with name \""
- + strValue
- + "\" in top level component in consuming page. "
- + "Page author error.");
- continue;
- }
+ // Find the attribute on the top level component
+ valueExpression = (ValueExpression) topLevelComponent.getAttributes().
+ get(attrName);
+ if (null == valueExpression) {
+ // PENDING error message in page?
+ logger.severe("Unable to find attribute with name \""
+ + attrName
+ + "\" in top level component in consuming page. "
+ + "Page author error.");
+ continue;
+ }
 
- // lazily initialize this local variable
- if (null == expressionFactory) {
- expressionFactory = context.getApplication().getExpressionFactory();
- }
+ // lazily initialize this local variable
+ if (null == expressionFactory) {
+ expressionFactory = context.getApplication().getExpressionFactory();
+ }
 
- // If the attribute is one of the pre-defined
- // MethodExpression attributes
- if (strValue.equals("action")) {
+ // If the attribute is one of the pre-defined
+ // MethodExpression attributes
+ if (attrName.equals("action")) {
                         expectedReturnType = Object.class;
                         expectedParameters = new Class[]{};
                         toApply = expressionFactory.createMethodExpression(context.getELContext(),
                                 valueExpression.getExpressionString(),
                                 expectedReturnType, expectedParameters);
                         ((ActionSource2) target).setActionExpression(toApply);
- } else if (strValue.equals("actionListener")) {
- expectedReturnType = Void.TYPE;
- expectedParameters = new Class[]{
- ActionEvent.class
- };
- toApply = expressionFactory.createMethodExpression(context.getELContext(),
- valueExpression.getExpressionString(),
- expectedReturnType, expectedParameters);
- ((ActionSource2) target).addActionListener(new MethodExpressionActionListener(toApply));
- } else if (strValue.equals("validator")) {
- expectedReturnType = Void.TYPE;
- expectedParameters = new Class[]{
- FacesContext.class,
- UIComponent.class,
- Object.class
- };
- toApply = expressionFactory.createMethodExpression(context.getELContext(),
- valueExpression.getExpressionString(),
- expectedReturnType, expectedParameters);
- ((EditableValueHolder) target).addValidator(new MethodExpressionValidator(toApply));
- } else if (strValue.equals("valueChangeListener")) {
- expectedReturnType = Void.TYPE;
- expectedParameters = new Class[]{
- ValueChangeEvent.class
- };
- toApply = expressionFactory.createMethodExpression(context.getELContext(),
- valueExpression.getExpressionString(),
- expectedReturnType, expectedParameters);
- ((EditableValueHolder) target).addValueChangeListener(new MethodExpressionValueChangeListener(toApply));
- } else {
- // If the attribute is not one of the pre-defined
- // MethodExpression attributes, look it up reflectively,
- // assuming there is a setter of type MethodExpression
+ } else if (attrName.equals("actionListener")) {
+ expectedReturnType = Void.TYPE;
+ expectedParameters = new Class[]{
+ ActionEvent.class
+ };
+ toApply = expressionFactory.createMethodExpression(context.getELContext(),
+ valueExpression.getExpressionString(),
+ expectedReturnType, expectedParameters);
+ ((ActionSource2) target).addActionListener(new MethodExpressionActionListener(toApply));
+ } else if (attrName.equals("validator")) {
+ expectedReturnType = Void.TYPE;
+ expectedParameters = new Class[]{
+ FacesContext.class,
+ UIComponent.class,
+ Object.class
+ };
+ toApply = expressionFactory.createMethodExpression(context.getELContext(),
+ valueExpression.getExpressionString(),
+ expectedReturnType, expectedParameters);
+ ((EditableValueHolder) target).addValidator(new MethodExpressionValidator(toApply));
+ } else if (attrName.equals("valueChangeListener")) {
+ expectedReturnType = Void.TYPE;
+ expectedParameters = new Class[]{
+ ValueChangeEvent.class
+ };
+ toApply = expressionFactory.createMethodExpression(context.getELContext(),
+ valueExpression.getExpressionString(),
+ expectedReturnType, expectedParameters);
+ ((EditableValueHolder) target).addValueChangeListener(new MethodExpressionValueChangeListener(toApply));
+ } else {
+ // There is no explicit methodExpression property on
+ // an inner component to which this MethodExpression
+ // should be retargeted. In this case, replace the
+ // ValueExpression with a method expresson.
+
+ // Pull apart the methodSignature to derive the
+ // expectedReturnType and expectedParameters
 
+ // PENDING(rlubke,jimdriscoll) bulletproof this
+
+ assert(null != methodSignature);
+ methodSignature = methodSignature.trim();
+
+ // Get expectedReturnType
+ int j, i = methodSignature.indexOf(" ");
+ if (-1 != i) {
+ strValue = methodSignature.substring(0, i);
+ try {
+ expectedReturnType = Util.getTypeFromString(strValue);
+ } catch (ClassNotFoundException cnfe) {
+ logger.log(Level.SEVERE,
+ "Unable to determine expected return type for " +
+ methodSignature, cnfe);
+ continue;
+ }
+ } else {
+ logger.severe("Unable to determine expected return type for " +
+ methodSignature);
+ continue;
+ }
+
+ // derive the arguments
+ i = methodSignature.indexOf("(");
+ if (-1 != i) {
+ j = methodSignature.indexOf(")", i+1);
+ if (-1 != j) {
+ strValue = methodSignature.substring(i + 1, j);
+ if (0 < strValue.length()) {
+ String [] params = strValue.split(",");
+ expectedParameters = new Class[params.length];
+ boolean exceptionThrown = false;
+ for (i = 0; i < params.length; i++) {
+ try {
+ expectedParameters[i] =
+ Util.getTypeFromString(params[i]);
+ } catch (ClassNotFoundException cnfe) {
+ logger.log(Level.SEVERE,
+ "Unable to determine expected return type for " +
+ methodSignature, cnfe);
+ exceptionThrown = true;
+ break;
+ }
+ }
+ if (exceptionThrown) {
+ continue;
+ }
+
+ } else {
+ expectedParameters = new Class[]{};
+ }
+ }
+
+ }
+
+ assert(null != expectedReturnType);
+ assert(null != expectedParameters);
+
+ toApply = expressionFactory.createMethodExpression(context.getELContext(),
+ valueExpression.getExpressionString(),
+ expectedReturnType, expectedParameters);
+ topLevelComponent.getAttributes().put(attrName, toApply);
+
+
+ }
                     }
                 }
             }
-
         }
-
+
     }
     
     
Index: jsf-ri/src/com/sun/faces/util/Util.java
===================================================================
--- jsf-ri/src/com/sun/faces/util/Util.java (revision 5806)
+++ jsf-ri/src/com/sun/faces/util/Util.java (working copy)
 -280,8 +280,35 @@
         throws FacesException {
         return (context.getApplication().getStateManager());
     }
+
+ public static Class getTypeFromString(String type) throws ClassNotFoundException {
+ Class result = null;
+ if (type.equals("byte")) {
+ result = Byte.TYPE;
+ } else if (type.equals("short")) {
+ result = Short.TYPE;
+ } else if (type.equals("int")) {
+ result = Integer.TYPE;
+ } else if (type.equals("long")) {
+ result = Long.TYPE;
+ } else if (type.equals("float")) {
+ result = Float.TYPE;
+ } else if (type.equals("double")) {
+ result = Double.TYPE;
+ } else if (type.equals("boolean")) {
+ result = Boolean.TYPE;
+ } else if (type.equals("char")) {
+ result = Character.TYPE;
+ } else if (type.equals("void")) {
+ result = Void.TYPE;
+ } else {
+ result = Util.loadClass(type, Void.TYPE);
+ }
 
+ return result;
+ }
 
+
     public static ViewHandler getViewHandler(FacesContext context)
         throws FacesException {
         // Get Application instance
Index: jsf-demo/ezcomp02/src/main/webapp/WEB-INF/composite-test.taglib.xml
===================================================================
--- jsf-demo/ezcomp02/src/main/webapp/WEB-INF/composite-test.taglib.xml (revision 5806)
+++ jsf-demo/ezcomp02/src/main/webapp/WEB-INF/composite-test.taglib.xml (working copy)
 -38,11 +38,10 @@
 
 -->
 
-<!DOCTYPE facelet-taglib PUBLIC
- "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
- "http://java.sun.com/dtd/facelet-taglib_1_0.dtd">
-
-<facelet-taglib>
+<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>http://domain.com/path</namespace>
     <composite-library-name>compositeTest</composite-library-name>
 </facelet-taglib>
Index: jsf-demo/ezcomp02/src/main/webapp/WEB-INF/web.xml
===================================================================
--- jsf-demo/ezcomp02/src/main/webapp/WEB-INF/web.xml (revision 5806)
+++ jsf-demo/ezcomp02/src/main/webapp/WEB-INF/web.xml (working copy)
 -70,7 +70,7 @@
     </context-param>
     <context-param>
         <param-name>facelets.LIBRARIES</param-name>
- <param-value>/WEB-INF/composite-test.taglib.xml</param-value>
+ <param-value>/WEB-INF/composite-test.taglib.xml;/WEB-INF/test-schema.taglib.xml</param-value>
     </context-param>
 
 
Index: jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml
===================================================================
--- jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml (revision 5806)
+++ jsf-demo/ezcomp02/src/main/webapp/resources/ezcomp/loginPanel.xhtml (working copy)
 -59,7 +59,7 @@
   <composite:attribute name="pinLabel" default="PIN" />
   <composite:attribute name="loginLabel" default="Login" />
   <composite:attribute name="model" required="true"/>
- <composite:attribute name="action" method-signature="java.lang.Object action()" applyTo="loginEvent"/>
+ <composite:attribute name="action" method-signature="java.lang.Object action()" targets="loginEvent"/>
 
 
   <composite:editableValueHolder name="usernameInput" />
Index: jsf-demo/ajax-switchlist/web/resources/switchlist/switchlist.xhtml
===================================================================
--- jsf-demo/ajax-switchlist/web/resources/switchlist/switchlist.xhtml (revision 5806)
+++ jsf-demo/ajax-switchlist/web/resources/switchlist/switchlist.xhtml (working copy)
 -57,8 +57,8 @@
     <composite:attribute name="selected2" required="true"/>
     <composite:attribute name="items1" required="true"/>
     <composite:attribute name="items2" required="true"/>
- <composite:attribute name="move1to2" required="true" method-signature="void f1(javax.faces.event.ActionEvent)" />
- <composite:attribute name="move2to1" required="true" method-signature="void f2(javax.faces.event.ActionEvent)" />
+ <composite:attribute name="move1to2" targets="move1to2" required="true" method-signature="void f1(javax.faces.event.ActionEvent)" />
+ <composite:attribute name="move2to1" targets="move2to1" required="true" method-signature="void f2(javax.faces.event.ActionEvent)" />
 
 </composite:interface>





-- 
| ed.burns_at_sun.com  | office: 408 884 9519 OR x31640
| homepage:         | http://ridingthecrest.com/