[jsr-314-open] #{cc} semantics
Andy Schwartz
andy.schwartz at oracle.com
Tue Sep 15 18:34:49 EDT 2009
Ryan, All -
Breaking this topic off into a separate thread, though I am impressed
with the length of the "<h:dataTable> binding vs. ui:repeat" thread. :-)
Ryan Lubke wrote:
> On 9/7/09 6:06 PM, Andy Schwartz wrote:
>> Thanks Lincoln. I haven't had time to debug this, but I have a
>> theory about what might be happening. In your sample:
>>
>>> <a:editText value="#{cc.attrs.task.text}"
>>> rendered="#{!cc.attrs.disabled}">
>>> *<f:actionListener for="submit"
>>> action="#{taskController.saveTaskAjax(cc.attrs.story,
>>> cc.attrs.task)}" /> *
>>> </a:editText>
>>
>> We expect "cc" to resolve to the containing composite component (ie.
>> to the <socialpm:taskBlock> component). I wouldn't be surprised if
>> what is actually happening is that "cc" is being resolved to the
>> <a:editText> composite component instead.
> Yep, that's what is happening.
>> One reason why I suspect this might be happening is that I know that
>> Ryan has investigated/resolved similar problems not too long ago.
> The problem we resolved was the passing of #{cc.attrs} attributes
> between nested composite components.
> For this case, the spec recommends using cc.parent.attrs.story and
> cc.parent.attrs.task, where parent resolves
> to the nearest composite component parent of the current composite
> component.
I am concerned about this behavior. It isn't clear to me whether the
spec is explicit about this behavior, or whether this is something that
happens to fall out of the implementation. Either way, the current
behavior seems counterintuitive to me, and, well... wrong.
My feeling is that when a composite component author uses a #{cc}
expression in a composite component implementation, eg:
<composite:implementation>
<h:outputText value="#{cc.attrs.value}">
</composite:implementation>
The correct behavior (the behavior expected by the composite component
author) is to resolve the #{cc} expression relative to where the
expression is defined - not relative to where it happens to end up in
the component tree. So, for example, I believe that these three uses of
the #{cc.attrs.value} expression should all evaluate to the same value:
<composite:implementation>
<!-- 1. Expression directly in the implementation -->
<h:outputText value="#{cc.attrs.value}">
<!-- 2. Expression in non-composite component facet -->
<bar:someJavaComposite>
<f:facet name="someFacet">
<h:outputText value="#{cc.attrs.value}">
</f:facet>
</bar:someJavaComponent>
<!-- 3. Expression in composite component facet -->
<foo:someCompositeComponent>
<f:facet name="someFacet">
<h:outputText value="#{cc.attrs.value}">
</f:facet>
</foo:someCompositeComponent>
</composite:implementation>
The fact that the #{cc.attrs.value} expression evaluates the same in
cases #1 and #2 but not in case #3 is non-obvious and is going to be
confusing for our users. The fact that Lincoln and I were confused
about this is a good indication that others will be as well.
I am not happy with the work around of using #cc.parent.attrs, since
this means that:
1. The user must recognize that the component in question is a composite
component and code the expression differently. While at the moment it
is fairly easy to determine whether a particular component is a
composite or not (by looking at the namespace declaration), I think that
we should strive to blur these lines rather than reinforce them. For
example, I would like to see the ability to define a single tag library
that consists of both composite and non-composite components, making the
choice of component implementation more transparent to the user.
2. Once the user has coded the expression in a composite
component-specific way, this introduces a dependency on the fact that
the component in question is a composite component - a dependency that
shouldn't be necessary for this particular case. Such dependencies
inhibit flexibility. If in the future the provider of the composite
component decides to switch to a Java-based component, this will break
any code (or EL expression) that assumes that the component is a
composite. We should keep such dependencies to a minimum.
3. This also introduces a subtle dependency on the composite component's
implementation. What if the composite component implementation passes
the expression along to yet another nested composite component? Does
the user now need to specify an expression that pops out multiple levels
of parents?
While it is certainly trickier to deal with from an implementation
perspective, I believe that it is very important that we re-consider the
current behavior and consider spec'ing that #{cc} expressions always
resolve relative to the context in which they are defined. I feel that
the current behavior violates the principle of least surprise (both
Lincoln and I were surprised) and also breaks encapsulation (ie.
introduces implementation-specific dependencies).
Leaving aside questions of how we might implement my preferred behavior
for the moment... Does anyone have comments on which behavior makes
sense from a spec/end user perspective?
Andy
More information about the jsr-314-open-mirror
mailing list