[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