Sunday, September 4, 2011

Simple Java based JSF custom component

Even though in JSF components have always been a central thing, actually creating them required a ridiculous amount of tedious work in JSF 1.x. Not only did you had to create the actual component, it also required you to:
  • Register the component in an XML file
  • Create a tag handler class, where you referenced the component by its registered name
  • Register the tag in .tld file.

You were also more or less supposed to create a separate renderer class, and although this actually has always been optionally, people seemed to interpret it as being a required part as well. Although none of this was really difficult, the sheer amount of work prevented everyone but component library builders from creating components.

JSF 2.0 addressed all of these concerns by introducing composite components, where you are able to create first-class components just by putting some existing components and/or markup in a Facelets file. For the majority of use cases where application builders needed their own customized components, this is actually all that's needed.

For some cases however a Java based component is still a more natural fit. Although not as simple to create as composite components, creating Java based custom components has actually been simplified as well. Of the steps outlined above, only a registration for the tag is still required. The actual component can be rather simple:

components/CustomComponent.java

@FacesComponent("components.CustomComponent")
public class CustomComponent extends UIComponentBase {

    @Override
    public String getFamily() {        
        return "my.custom.component";
    }
    
    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        
        String value = (String) getAttributes().get("value");
        
        if (value != null) {        
            ResponseWriter writer = context.getResponseWriter();
            writer.write(value.toUpperCase());
        }
    }
}

Unfortunately, a registration in an XML file is still required in JSF 2.1 to use this as a tag (note, that in JSF 2.2 this isn't required anymore):

META-INF/my.taglib.xml

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
    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"
    version="2.0">

    <namespace>http://example.com/test</namespace>
    
    <tag>
        <tag-name>customComponent</tag-name>
 <component>
            <component-type>components.CustomComponent</component-type>
        </component>
    </tag>
    
</facelet-taglib>

The custom component can now be used on a Facelet as follows:

page.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:test="http://example.com/test"
>
    <h:body>     
        <test:customComponent value="test"/>        
    </h:body>
</html>

As shown, creating a Java based JSF component that simply renders something is not that complicated. Although composite components should generally be preferred, Java based ones can come in handy and it's an important extra tool.

It's a shame perhaps the XML registration is still needed in JSF 2.1, but luckily there was a feature request in the JSF spec JIRA that made it largely unnecessary for JSF 2.2. Hopefully the actual Java code can also be further simplified if the family and component name would be defaulted in a future JSF version (the last e.g. to the fully qualified class name).

Arjan Tijms

No comments:

Post a Comment