[ https://issues.apache.org/jira/browse/MYFACES-2946?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Leonardo Uribe resolved MYFACES-2946. ------------------------------------- Resolution: Fixed > composite:attribute "targets" property does not match with > ViewDeclarationLanguage.retargetMethodExpressions > ------------------------------------------------------------------------------------------------------------ > > Key: MYFACES-2946 > URL: https://issues.apache.org/jira/browse/MYFACES-2946 > Project: MyFaces Core > Issue Type: Bug > Components: JSR-314 > Affects Versions: 2.0.2 > Reporter: Leonardo Uribe > Assignee: Leonardo Uribe > Fix For: 2.0.3-SNAPSHOT > > Attachments: MYFACES-2946-1.patch > > > Some days ago, it was mentioned on myfaces dev list that "targets" > attribute does not seem to work as expected. After review the available > documentation and doing some test, my conclusion was the spec is good, > but this part needs a little bit more documentation (and fix some > bugs), because there are use cases that are causing problems to users. > Some of these problems has been already mentioned (spec issue 755) but > my intention here is do a full and detailed analysis. > The property "targets" is used for these tags: > composite:actionSource > composite:editableValueHolder > composite:valueHolder > composite:clientBehavior > composite:attribute > For the first four cases, this property is used by : > ViewDeclarationLanguage.retargetAttachedObjects(FacesContext context, > UIComponent topLevelComponent, > List<AttachedObjectHandler> handlers) > In JSF 2.0 rev A it was made explicit the need to handle nested > composite component with this lines: > "... The implementation must support retargeting attached objects from > the top level compsite component to targets that are composite and > non-composite components ...." > This is ok ;-). > The problem is the description about how composite:attribute "targets" > property works does not match with the algorithm for: > ViewDeclarationLanguage.retargetMethodExpressions(FacesContext context, > UIComponent topLevelComponent) > Here is the documentation about composite:attribute "targets": > "... If this element has a method-signature attribute, > the value of the targets attribute must be interpreted as a space > (not tab) separated list of client ids (relative to the top level > component) of components within the <composite:implementation> section. > Space is used as the delimiter for compatibility with the IDREFS and > NMTOKENS data types from the XML Schema. > Each entry in the list must be interpreted as the id of an inner > component to which the MethodExpression from the composite component > tag in the using page must be applied. > If this element has a method-signature attribute, but no targets > attribute, the value of the name attribute is used as the single entry > in the list. > If the value of the name attribute is not one of the special values > listed in the description of the name attribute, targets (or its > derived value) need not correspond to the id of an inner component ...". > At this point everything seems to be ok. But look this documentation > (I'll put the important points): > "..... > # Get the value of the targets attribute. If the value is a ValueExpression > evaluate it. If there is no targets attribute, let the name of the > metadata element be the evaluated value of the targets attribute. > # Interpret targets as a space (not tab) separated list of ids. For each > entry > in the list: > ...... > # If name is equal to the string "action" without the quotes, call > ActionSource2.setActionExpression(javax.el.MethodExpression) on target, > passing attributeMethodExpression. > # If name is equal to the string "actionListener" without the quotes, > call > ActionSource.addActionListener(javax.faces.event.ActionListener) on > target, > passing attributeMethodExpression wrapped in a > MethodExpressionActionListener. > # If name is equal to the string "validator" without the quotes, call > EditableValueHolder.addValidator(javax.faces.validator.Validator) on > target, > passing attributeMethodExpression wrapped in a > MethodExpressionValidator. > # If name is equal to the string "valueChangeListener" without the > quotes, call > > EditableValueHolder.addValueChangeListener(javax.faces.event.ValueChangeListener) > > on target, passing attributeMethodExpression wrapped in a > MethodExpressionValueChangeListener. > # Otherwise, assume that the MethodExpression should be placed in the > components attribute set. The runtme must create the MethodExpression > instance based on the value of the "method-signature" attribute. > ....." > My first interpretation of this javadoc was that "targets" only has sense for > "action", > "actionListener", "validator" and "valueChangeListener". But note if that's > true, > someone could expect something like the description on > retargetAttachedObjects, right? > The current behavior (Mojarra 2.0.3 and Myfaces 2.0.2) is the same, if we > have two > nested composite components, that will throw a ClassCastException. There is a > issue already > open for this one: > https://javaserverfaces-spec-public.dev.java.net/issues/show_bug.cgi?id=755 > There are two possible alternatives here: > 1. Implement the algorithm proposed for retargetMethodExpressions and ignore > composite:attribute "targets" property says. > 2. Implement the expected behavior of composite:attribute "targets" property > and make > some changes to retargetMethodExpressions algorithm. > The intention is take option 2 and include it for JSF 2.0, because in theory > should be > handled as an implementation detail of the algorithm (anyway it could be good > to update > the documentation with the same advice used for retargetAttachedObjects). > For "action", "actionListener", "validator" and "valueChangeListener" it is > clear that > the action to take is something like this: > - If target is a composite component and that one "retarget" to other > components and > additionally does not implements [ActionSource2/EditableValueHolder], call: > > targetComponent.getAttributes().put(attributeName, > attributeNameValueExpression); > > and call retargetMethodExpressions recursively. Take care of apply the > method twice > and if the property pointed by "attributeName" was already set, revert its > effects. > > The tricky part is how to handle generic method expression properties. The > javadoc says: > ".... > # Otherwise, assume that the MethodExpression should be placed in the > components attribute set. The runtme must create the MethodExpression > instance based on the value of the "method-signature" attribute. > ....." > But I have identified three valid cases: > 1. testSimpleAttributeMethodExpressionEmpty.xhtml (Using an EL #{cc} > reference) > <testComposite:simpleAttributeMethodExpressionEmpty id="cc1" > customMethod="#{methodExpressionBean.doSomethingFunny}"> > </testComposite:simpleAttributeMethodExpressionEmpty> > simpleAttributeMethodExpressionEmpty.xhtml > <composite:interface> > <composite:attribute > name="customMethod" > method-signature="String doSomething(String)"/> > </composite:interface> > <composite:implementation> > <tc:testComponent id="testComponent" > customMethod="#{cc.attrs.customMethod}"/> > </composite:implementation> > 2. testSimpleAttributeMethodExpressionTarget.xhtml (Using "targets" to call > a property setter directly) > <testComposite:simpleAttributeMethodExpressionTarget id="cc1" > customMethod="#{methodExpressionBean.doSomethingFunny}"> > </testComposite:simpleAttributeMethodExpressionTarget> > > simpleAttributeMethodExpressionTarget.xhtml > > <composite:interface> > <composite:attribute > name="customMethod" > method-signature="String doSomething(String)" > targets="testComponent"/> > </composite:interface> > <composite:implementation> > <tc:testComponent id="testComponent"/> > </composite:implementation> > > 3. testCompositeAttributeMethodExpressionTarget.xhtml (Using "targets", > but the target component is a composite one) > <testComposite:compositeAttributeMethodExpressionTarget id="cc1" > customMethod="#{methodExpressionBean.doSomethingFunny}"> > </testComposite:compositeAttributeMethodExpressionTarget> > compositeAttributeMethodExpressionTarget.xhtml > <composite:interface> > <composite:attribute > name="customMethod" > method-signature="String doSomething(String)" > targets="simpleAttributeMethodExpressionTarget"/> > </composite:interface> > <composite:implementation> > <testComposite:simpleAttributeMethodExpressionTarget > id="simpleAttributeMethodExpressionTarget"/> > </composite:implementation> > > simpleAttributeMethodExpressionTarget.xhtml (could be like in 1 or 2) > The case (1) actually works but the case (2) and (3) does not work on both > MyFaces 2.0.2 and Mojarra 2.0.3 . -- This message is automatically generated by JIRA. - You can reply to this email to add a comment to the issue online.