You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by "Leonardo Uribe (JIRA)" <de...@myfaces.apache.org> on 2011/06/10 05:05:00 UTC

[jira] [Updated] (MYFACES-3169) ui:param and c:set implementations does not work as expected

     [ https://issues.apache.org/jira/browse/MYFACES-3169?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Leonardo Uribe updated MYFACES-3169:
------------------------------------

    Status: Patch Available  (was: Open)

> ui:param and c:set implementations does not work as expected
> ------------------------------------------------------------
>
>                 Key: MYFACES-3169
>                 URL: https://issues.apache.org/jira/browse/MYFACES-3169
>             Project: MyFaces Core
>          Issue Type: Bug
>          Components: JSR-314
>    Affects Versions: 2.0.8, 2.1.1
>            Reporter: Leonardo Uribe
>            Assignee: Leonardo Uribe
>
> Original message sent to jsr344-experts and users mailing list:
> Checking how ui:param and c:set works and its relationship with facelets 
> VariableMapper, I notice the original implementation that comes from facelets 
> does not work like a page developer should expect. In fact, in some situations
> ui:param and c:set implementation is just the same.
> The consequence of this situation is there are ways to write code that just 
> should not be allowed, because it breaks the intention of those tags. JSF 
> implementations should fix this, and maybe if it is required add more 
> documentation specifying these tags better.
> The first case is c:set. This is the description on facelets taglibdoc:
> "... Sets the result of an expression evaluation based on the value of the 
> attributes. If 'scope' the is present, but has a zero length or is equal 
> to the string 'page', TagException is thrown with an informative error 
> message, ensuring page location information is saved. ..."
> "... This handler operates in one of two ways.
> 1. The user has set 'var', 'value' and (optionally) 'scope' attributes.
> 2. The user has set 'target', 'property', and 'value' attributes.
> The first case takes precedence over the second ..."
> The buggy behavior of this tag can be seen when it is used in this way:
> <c:set var="someVar" value="someValue"/>
> Look the part that says "... if 'scope' the is present, but has zero length or
> is equal to the string 'page' ..." . In JSP, it exists a page context and
> in that context, the variable has scope to the current page. Since in that
> case there are no template tags, this variable cannot be located on other 
> pages included with jsp:include or whatever you use. 
> The current implementation of c:set that comes from facelets 1.1.x does not
> implements the original intention of this tag in jsp, and instead it uses
> VariableMapper instance obtained through FaceletContext (which is instance
> of ELContext). Since both JSF 2.0 implementations comes from the original 
> facelets 1.1.x code, you can see the following problems: 
> cset1.xhtml
> <c:set var="someVar" value="someValue"/>
> <ui:decorate template="cset1_1.xhtml">
>    <!-- ... -->
> </ui:decorate>
> cset1_1.xhtml
> <ui:composition>
>    <h:outputText value="#{someVar}"/>
> </ui:composition>
> The previous code in practice will output "someValue", but it should not, 
> because "someVar" should be only available on the current .xhtml page, in
> this case cset1.xhtml. 
> Now consider this more realistic example:
> cset2.xhtml
> <c:set var="someVar" value="someValue"/>
> <ui:decorate template="cset2_1.xhtml">
>    <!-- ... -->
>    <ui:define name="header">
>        <h:outputText value="#{someVar}"/>
>    </ui:define>
> </ui:decorate>
> cset2_1.xhtml
> <ui:composition>
>    <c:set var="someVar" value="badValue"/>
>    
>    <!-- ... something with someVar ... -->
>    
>    <ui:insert name="header"/>
> </ui:composition>
> In practice the output will be "badValue", but it should be "someValue",
> again because c:set intention is to define a value that should be
> available only on the current page. This problem is also valid if you
> replace ui tags with a composite component and cc:insertXXX tags.
> Now take a look at this one:
> cset3.xhtml
> <c:set var="someVar" value="someValue"/>
> <ui:decorate template="cset3_1.xhtml">
>     <!-- ... code without use ui:param ... -->
> </ui:decorate>
> <h:outputText value="#{someVar}"/>
> cset3_1.xhtml
> <ui:composition>
>    <c:set var="someVar" value="badValue"/>
>    <!-- ... something with someVar ... -->
> </ui:composition>
> In practice the output will be again "badValue", but it is interesting to note
> that if you use ui:param, the example will work again, because a
> VariableMapperWrapper is used, discarding the bad value after ui:decorate 
> ends.
> Things start to get worse when you see how ui:param works:
>     String nameStr = this.name.getValue(ctx);
>     ValueExpression valueVE = this.value.getValueExpression(ctx, Object.class);
>     ctx.getVariableMapper().setVariable(nameStr, valueVE);
>         
> It is the same thing as c:set!!!!! . 
>     if (this.scope != null)
>     {
>         /* ... Does this exception really has sense ??? ... */
>         if ("page".equals(scopeStr))
>         {
>             throw new TagException(tag, "page scope is not allowed");
>         }
>         /* ... some stuff that works well ...*/
>     } else {
>         ctx.getVariableMapper().setVariable(varStr, veObj);
>     }
> Why this code hasn't been broken before? because nobody has ever use c:set and
> ui:param with exactly the same var name. Maybe because on facelets dev 
> documentation:
> http://facelets.java.net/nonav/docs/dev/docbook.html
> says this:
> "... Table 3.5. <c:set/> (Avoid if Possible) ..."
> Really there are some particular situations where c:set is useful.
> There are a lot more examples I tried on ui:param that just don't work. But
> the big question is how c:set and ui:param should work?
> - c:set using only 'var' and 'value' should define the variable only as 
> "page" scoped, just like the old jstl tag does and the current spec javadoc
> says.
> - ui:param should define a variable "template" scoped, that means it applies
> to both template client and templates. It should be propagated through 
> ui:composition, ui:decorate, ui:define and ui:insert, but it should not pass
> composite components, because this one defines a different template resolution
> context (hack only on MyFaces, but valid for JSF). It should not pass on
> nested templates case (nested ui:composition or ui:decorate). 
> - The facelets taglibdoc of ui:param says:
> "... Use this tag to pass parameters to an included file (using ui:include), 
> or a template (linked to either a composition or decorator). Embed ui:param 
> tags in either ui:include, ui:composition, or ui:decorate to pass the 
> parameters. ..."
> JSF implementation should do exactly what it says here.
> Note all this should work using a more elaborate hack over VariableMapper,
> because it is not possible to use another alternative here. One idea is 
> create a component that defines a "local" page scope just like {} does 
> in java code, but maybe is too much for something than in practice should
> be simple.
> I think this should be fixed. Obviously I'm doing an interpretation of the
> few documentation available, but note at the end a "final word" should be
> done here at spec level to keep compatibility between JSF implementations.

--
This message is automatically generated by JIRA.
For more information on JIRA, see: http://www.atlassian.com/software/jira