One comment (which I've already given)-
In the ajax tag, we're delimiting clientids with spaces.
We should delimit them the same way in each place.
Andy is adamant on using spaces, since they can never be a part of a
clientId (whereas commas, apparently, can).
So, I think we should change that portion of the code to be space
delimited...
Jim
Ed Burns wrote:
> 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><composite:implementation></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>
>
>
>
>
>