jsfjsf-2faceletsmojarratagfile

Custom tag attributes are leaking into children


Our application is using Mojarra 2.1.29-03 and we are having a problem with attributes in our custom tags as they are being copied to nested tags as well.

For example, given the following tag definition:

cc.taglib.xml

<?xml version="1.0" encoding="UTF-8" ?>
<facelet-taglib version="2.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd">
    <namespace>http://temp.com/jsf/customcomponents</namespace>
    <tag>
        <tag-name>wrapper</tag-name>
        <source>wrapper.xhtml</source>
        <attribute>
            <description>The style class for the component</description>
            <name>styleClass</name>
        </attribute>
    </tag>
</facelet-taglib>

wrapper.xhtml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
    <ui:component xmlns:ui="http://java.sun.com/jsf/facelets">
        <div style="border: 1px solid black; margin: 5px;">
            <p>styleClass: #{styleClass}</p>
            <ui:insert />
        </div>
    </ui:component>
</html>

And a client page:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:cc="http://temp.com/jsf/customcomponents">
     <h:body>
        <cc:wrapper styleClass="cc-style">
            <cc:wrapper />
        </cc:wrapper>
    </h:body>
</html>

The result is as follows:

styleClass: cc-style

styleClass: cc-style

... so the styleClass attribute is also being applied to the inner tag even though the client page does not set it.

We have noted that we can workaround this by processing all our client pages to set styleClass="" if it is not explicitly set but this is an approach we would like to avoid (it's a very ugly solution and cannot be enforced going forward).

Is this a bug? Is there any way to work around it other than that mentioned above - preferably with the workaround in the tag rather than the client pages?

Thanks Ivor


Solution

  • This is not strictly a bug, but this is indeed unintuitive and undesired behavior which should have been addressed in the JSF/Facelets spec.

    The work around solution is not trivial, a custom taghandler is needed to clear out the Facelet scope. JSF utility library OmniFaces has since version 2.1 exactly such one: <o:tagAttribute> (source code here).

    Usage (do note that prolog, doctype and html tags are unnecessary, this is the file in its entirety):

    <ui:composition 
        xmlns="http://www.w3.org/1999/xhtml"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:o="http://omnifaces.org/ui"
    >
        <o:tagAttribute name="styleClass" />
    
        <div style="border: 1px solid black; margin: 5px;">
            <p>styleClass: #{styleClass}</p>
            <ui:insert />
        </div>
    </ui:composition>
    

    Unrelated to the concrete problem, this is not a custom component, but a tagfile. And, in JSF 2.x, the term "cc" is usually associated with composite components, which is a completely different subject altogether. To get your knowledge and terminology right (so that you don't confuse yourself or others while reading your or other's code), head to When to use <ui:include>, tag files, composite components and/or custom components?