Hi
I checked in deep how attribute for composite components works, and here is
what I found.
This is the javadoc of cc:attribute type:
"... Declares that this attribute must be a ValueExpression whose expected
type is given by the value of this attribute. If not specified, and no
"method-signature" attribute is present, java.lang.Object is assumed. This
attribute is mutually exclusive with the "method-signature" attribute. If
both attributes are present, the "method-signature" attribute is ignored.
..."
MyFaces (2.0.3 and earlier) implemented what javadoc says, but in practice
Mojarra (tested 2.0.3 and 2.1.0 snapshot branch) behaves different in this
case. For example, if it is written this:
<cc:attribute name="foo" type="java.lang.Integer"/>
With the following component definition:
<comp:bar foo="5"/>
In MyFaces the String "5" is stored on the map, but in Mojarra an Integer 5
is. It is obvious the right behavior is the one shown by Mojarra, even if
the javadoc is to explicit about this fact.
Now think about a little bit more complex example:
<cc:attribute name="foo" type="java.lang.Integer"
default="5"/>
both MyFaces and Mojarra fails in this case, because the default is assumed
to be a String "5" and not an Integer 5.
It is obvious the author expect "type" attribute enforce the value to the
type using EL coercions, like it is done for all other components, right?
Maybe the javadoc is not explicit, but it is clear the way to go.
Now try to get a value programatically instead use EL expressions.
myCompositeBar.getAttributes.get("foo")
the default is just ignored. Why? by the spec, composite component default
values are handled by "Composite Component Attribute EL Resolver". This is
what JSF 2.0 spec section 5.6.6.2 says about it (getValue description)
"... get(): if the result of calling get() on the component attributes map
is null, and a default value was declared in the composite component
metadata, the value will be a ValueExpression. Evaluate it and return it.
Otherwise, simply return the value from the component attributes map. ..."
In my opinion, we should do that on UIComponent.getAttributes() map instead
on an EL resolver, after all we could use the value stored on BEANINFO_KEY
to get the descriptor and handle the default value only if all fails.
But here is the big question: It is really necessary to support that case?
The common case is lookup attributes map using an EL expression
#{cc.attrs.myproperty}. This could be necessary only if we do a composite
component with a custom component type and we need to play with properties
defined on the component class and the composite component definition, but
that's very exotic (but theorically possible).
Now it is possible to answer the questions (in my personal opinion, based on
the previous reasoning):
1. Should JSF implementations be making use of composite component metadata
(like "type") at runtime to enforce the intentions of the composite
component author?
Ans: Really this is already done, because ValueExpressions are created and
values are coerced taking into account the type, but we don't have any code
on the default component attribute map class that enforces it.
2. Should this behavior be specified?
Ans: the javadoc of cc:attribute type is incomplete and definitively needs
to be fixed.
3. Are there other places where we have similar metadata (eg. Facelets
taglib.xml files) that we should review as well?
Ans: User tag handlers does not have any semantic about how to handle
attributes, so there is nothing we can do or other places to review (after
all, one of the intentions of composite components is provide a transparent
way to create components with the flexibility of custom facelets tag
handlers).
What do we need to do? Fix the bugs on MyFaces and Mojarra related to this
issue.
regards,
Leonardo Uribe