Friday 7 June 2013

JSF 2.2 Pass-through attributes

Introduction

Until now, you could only use attributes on the JSF tags which where recognized by the component library.
Until recently, this made sense.  Those attributes are used to ‘configure’ the JSF tag and thus other attributes have no meaning for the component and thus not needed.
But that changed with the HTML 5 specification. One of the additions is that you can define and use your own attributes which can be used by for instance by your javascript code.
Now you no longer need to use class names to store metadata and thus your html code becomes cleaner.

JSF support

But this nice feature of HTML5 is a problem for the JSF framework. Since we have no way of specifying that additional parameters needs to be passed to the generated markup, there was no easy way of supporting them.
Of course you could define them with the <f:attribute> tag and write extensions for the renderers, but native support is of course needed.
And with the new JSF 2.2 specification, there is the possibility to support them.  The feature is called pass-through attributes. And technically that is also what is happening.  Those attributes are just passed to the generated markup.

Example, input placeholder

Now we can specify the hint for an input with the placeholder attribute without the need of the component library to support it (of course, our browser need to support the HTML 5 attribute)
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:p="http://xmlns.jcp.org/jsf/passthrough">
<h:head>
...
</h:head>
<h:body>
    <h:form>
        <h:inputText id="basic" value="#{bean.value}" p:placeholder="Enter text"/>
         ...
    </h:form>
    ...
</h:body>;

By marking attributes as belonging to the newly introduced namespace http://xmlns.jcp.org/jsf/passthrough, we tell the renderers that they need to copy it to the markup.  Besides the support for literal values (like in the example above) EL expression are also allowed.

As you can see, they have also changed the namespace to xmlns.jcp.org instead of java.sun.com to emphasis that the specs are a community process and not originating from a single company (or was it just to remove the name sun?).

Multiple attributes


If you have several pass-though attributes that you need to specify, there is another way of specifying them.

The core namespace (xmlns:f="http://xmlns.jcp.org/jsf/core") has an additional tag now, called passThroughAttributes. It has a reference to a Map that contains all the attributes that needs to be added. The key of the map must be of String type, the value is an object or EL expression.
<f:passThroughAttributes value=”#{service.nameValuePairs}” />

You no longer need to specify them one by one, but the drawback of it, if you ask me, is that those view related metadata is specified in Java code and not in the JSF view.

Support in component libraries


For those that are writing component libraries them self (or a few components), it is easy to support those pass-through attributes on your component as well.

On the UIComponent class, they have introduced a new method getPassThroughAttributes(boolean) that you can use to retrieve the discovered attributes.

It returns the info as a Map and you can iterate over this collection and write the information on the response stream.

As this approach is generic, you can put the code in a utility class/method and call it for every component you like to have support for the pass-through components.

Conclusion


With the new pass-through feature of the JSF 2.2 spec, it becomes easy to support the HTML5 data attributes.  It is as simple as specifying the attributes on the JSF tag prefixed with an alias for a specific namespace to identify them as pass-through.

Also the code to support the in your custom widgets is less then 10 lines long.

The only issue you could have is that for some JSF components, it is not always immediately clear where the pass-through attributes are placed in the HTML markup when the tag generates multiple JSF elements.