Hi
Just to summarize the conversation with Frank and Ed in Javaland:
1.The objective of
http://xmlns.jcp.org/jsf/passthrough is different
from
http://xmlns.jcp.org/jsf namespace. So the condition that says
that only tags with attributes using
http://xmlns.jcp.org/jsf
namespace should be processed by TagDecorator still remains.
2. Use jsf:binding in Mojarra does not work, but it is not in the
documentation of jsf:element. But the same is true for id attribute and
these attributes comes from UIComponentBase. This is a bug in Mojarra and
should be fixed.
3. I have explained to Frank that in some cases
http://xmlns.jcp.org/jsf
put attributes into normal component attribute map but sometimes it is
required to use the passthrough attribute map. "id", "binding", "rendered"
and "transient" should not be put on passthrough attribute map, but other
attributes should.
I have found new elements of judment about the special behavior that has
attribute with
http://xmlns.jcp.org/jsf that suggest we need a more
elaborated implementation. Take a look at this example:
<div jsf:binding="#{boxBean.box1}">
<f:ajax event="click" render="renderMe"/>
Hello World!
</div>
<h:panelGroup layout="block" id="renderMe">Hello</h:panelGroup>
I tested it with Frank against Mojarra 2.2.6 and it works. The "onclick"
attribute is rendered as expected. But before I had some problems with it,
but I couldn't remember what was wrong. Now let's change it a little bit:
<div jsf:binding="#{boxBean.box1}" onclick="alert('hello')">
<f:ajax event="click" render="renderMe"/>
Hello World!
</div>
It doesn't work, because the ajax code is not chained with the code inside
onclick property. But this alternative works:
<div jsf:binding="#{boxBean.box1}" jsf:onclick="alert('hello')">
<f:ajax event="click" render="renderMe"/>
Hello World!
</div>
There are some lines in JSF 2.2 spec (RenderKit javadoc) that says:
"... If there is a pass through attribute with the same name as a renderer
specific attribute, the pass through attribute takes precedence. ..."
In the example using just "onclick", it doesn't work because the passthrough
attribute takes precedence and ignore the code in the renderer. The code
is executed but when the attribute is being renderer by ResponseWriter, it
is ignored.
There is another case that is also related. Take a look at this example:
<input jsf:id="input" type="text" value="#{someBean.someValue}"/>
Should this work?. According to the rules of TagDecorator, this is translated
into a h:inputText component, but the "value" attribute is copied into the
passthrough attribute map and in the normal attribute map. By the rule
previously described in the spec, the renderer is effectively bypassed.
Thanks to Frank, it was clarified the right syntax for it:
<input jsf:id="input" type="text" jsf:value="#{someBean.someValue}"/>
In conclusion we have these 3 cases:
1. Attributes with jsf namespace that should be put on passthrough
attribute map.
<div jsf:style="noprint">
Hello World!
</div>
2. Attributes with jsf namespace that should be put on normal attribute map.
<div jsf:binding="#{boxBean.box1}">
Hello World!
</div>
or
<input jsf:id="input" type="text" jsf:value="#{someBean.someValue}"/>
3. Attributes without any namespace that could overlap attributes in the
normal component map that requires special treatement.
<div jsf:binding="#{boxBean.box1}" onclick="alert('hello')">
<f:ajax event="click" render="renderMe"/>
Hello World!
</div>
What should we do? What's the ideal behavior?
- First of all we need to recognize that in this case attributes marked with
empty namespace and with jsf namespace behave the same. The only special
property it has jsf namespace is that its presence in an attribute makes the
tag susceptible to be converted.
- If the attribute is declared by the component class, it should be added to
the component attribute map.
- If the attribute is declared by the component class, it should NOT be added
to the passthrough attribute map.
- If the attribute is NOT declared by the component class, it should be put
on the passthrough attribute map.
How can we detect if a component class has a property defined? there is no
standard way to do that, but each JSF implementation has the code deep inside
UIComponentBase implementation, specifically in the normal component
attribute map. But that suppose a problem, because in the moment the default
TagDecorator is active, there is not a component class yet. But the trick
can be done with a new Rule, but it will not be easy.
This strategy has the big advantage that the attributes are not duplicated, so
the state size is not doubled. The objective is avoid changes in the spec if
possible, so let's see what we can do.
regards
Leonardo
2014-03-25 2:12 GMT+01:00 Edward Burns <edward.burns_at_oracle.com>:
>>>>>> On Mon, 24 Mar 2014 13:39:21 +0100, Leonardo Uribe <lu4242_at_gmail.com> said:
>
> LU> But the user has reported another more troublesome combination:
>
> LU> <li jsf:class="toclevel-1 tocsection-2"/>
>
> LU> According to the spec it should not work. The javadoc of
> LU> javax.faces.view.facelets.TagDecorator
> LU> says this (already mentioned before):
>
> LU> "... If the current attribute's namespace is http://xmlns.jcp.org/jsf,
> LU> convertedTagAttribute's qualified name must be the current attribute's local
> LU> name and convertedTagAttribute's namespace must be the empty string. This
> LU> will have the effect of setting the current attribute as a proper property
> LU> on the UIComponent instance represented by this markup. ..."
>
> LU> If the intention of jsf namespace is put the attribute into the
> LU> attribute map, why that syntax should work, unless the attribute has
> LU> been explicitly declared on jsf:element component.
>
> I haven't checked the code, but I expect the reason it works is due to
> the old attribute/property transparency. First it looks for a
> "setClass" method on the UIComponent instance. Failing to find it, it
> calls UIComponent.getAttributes().put("class", "toclevel-1 tocsection-2").
>
> LU> I tried also this
> LU> combination:
>
> LU> <div jsf:style="noprint">
> LU> Hello World!
> LU> </div>
>
> LU> It works again, but it shouldn't.
>
> Again, I expect this causes UIComponent.getAttributes().put("style",
> "noprint").
>
> LU> But it is clear why it is an obvious combination. The same javadoc
> LU> of TagDecorator detects any attribute with the namespace "jsf" and
> LU> if it is found the tag is binded to a jsf:element component. The
> LU> related line says this:
>
> LU> "... If one or more of the attributes of the tag argument are in the
> LU> http://xmlns.jcp.org/jsf namespace, obtain a reference to decoratedTag as
> LU> described in the following steps and iterate through the list of TagDecorator
> LU> instances as described in the preceding step ..."
>
> Yes, that text is the catch-all that allows the whole passthru elements
> feature to work.
>
> LU> In practice, it seems an attribute using "jsf" namespace should be
> LU> added in both normal attribute map and passthrough attribute map. I
> LU> can't detect any problem at the moment, because the logic in the
> LU> default ResponseWriter keeps track of the rendered attributes, and
> LU> as long as no logical attributes are copied, things will be
> LU> fine. Here there is an example of the problem:
>
> LU> <div jsf:binding="#{boxBean.box1}">
> LU> Hello World!
> LU> </div>
>
> LU> In Mojarra this attribute is just ignored, so it doesn't work, but
> LU> in MyFaces it works, but if the attributes are copied in both maps,
> LU> this one will be a problem. So the algorithm should duplicate the
> LU> attributes that are not reserved like "id", "binding", "rendered" or
> LU> "transient".
>
> I would have to step through this in a debugger to authoritatively
> comment on what the spec intent is here, and therefore to clearly define
> what "in MyFaces it works" means in this case.
>
> LU> There are a couple of attributes that are implementation specific,
> LU> but since they are not declared in the markup, they do not have the
> LU> chance to be copied or overriden.
>
> I'd like to avoid having to do this.
>
> LU> It is curious this syntax does not work:
>
> LU> <div pt:style="noprint">
> LU> Hello World!
> LU> </div>
>
> LU> The tag is not converted into a jsf:element, so the compiler sees it as
> LU> html markup.
>
> I would need to see to that namespace the pt: attribute prefix is
> bound. If it is the xmlns.jcp.org pass through attribute namespace,
> then it should work and that is a bug.
>
> LU> I do not see any other choice than force the copy to the passthrough
> LU> attribute map of all attributes declared with jsf namespace. But I have
> LU> to warn about a side effect over the state. If the attributes are copied
> LU> twice, that means the state of that component is effectively doubled.
> LU> If PSS is properly implemented, it will not have a significant effect
> LU> over the state, because most of the time that part is not part of the
> LU> "delta" state of the component.
>
> I must understand why the copy is necessary.
>
> Ed
>
> --
> | edward.burns_at_oracle.com | office: +1 407 458 0017
> | 0 Work Days Til JavaLand 2014
> | 30 Work Days til JAX 2014