A simple JSF2 custom component

Introduction

Java Server Faces Version 2 offers two ways to write custom components. First you can write your component in Java. This option was already possible in JSF 1.x. JSF 2 introduced a new possiblility: composite components. With composite components you don't have to write a single line of java code. As the name implies, composite components are composed from existing JSF components. In this article I am going to describe the first possiblity: writing your component in Java.

A simple teaser

Assume you want to write a simple JSF component to display a teaser for a blog entry with a link to the article. The teaser only shows the first few lines of the blog entry. You can also make the teaser show an alternative text. In a first step I implement this feature in plain old HTML without the use of JSF custom components. The idea how to show only the first few lines of the article is to use a div with a predefined height an hidden overflow:

div.teaser {
  width:490px;
  height:400px;
  overflow: hidden
}

Now we can include the whole article, but only the first few lines are shown:

<div class="teaser">
    <ui:include src="/cleancode.xhtml" />
</div>
<p>
    <a href="wrapper.jsf?page=/cleancode.xhtml">
    [read on]
    </a>
</p>

The wrapper document wrapper.xhtml must include the referenced article (main.xhtml is just a facelet template):

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:c="http://java.sun.com/jsp/jstl/core">
    <h:body>
        <ui:composition template="/template/main.xhtml">
 
            <ui:define name="content">
                <ui:include src="\#{param['page']}" />
            </ui:define>
 
        </ui:composition>
    </h:body>
</html>

Now we want to write a JSF custom component that allows us to simplify the teaser as follows:

<cc:teaser url="/posts/cleancode.xhtml" styleClass="teaser">
    <ui:include src="/posts/cleancode.xhtml" />
</cc:teaser>

Writing the JSF teaser component

Have a look at the java class implementing our teaser component:

@FacesComponent(value = "at.halboffen.blog.jsf.component.Teaser")
public class Teaser extends UIComponentBase {
 
    private static final String STYLE_CLASS = "styleClass";
    private static final String SRC = "src";
 
    @Override
    public String getFamily() {
        return null;
    }
 
    @Override
    public void encodeBegin(FacesContext context)
    throws IOException {
 
        Map<String, Object> attributes = getAttributes();
        String style = (String) attributes.get(STYLE_CLASS);
 
        ResponseWriter responseWriter = context.getResponseWriter();
        responseWriter.startElement("div", null);
        responseWriter.writeAttribute("class", style, null);
 
    }
 
    @Override
    public void encodeEnd(FacesContext context)
    throws IOException {
 
        Map<String, Object> attributes = getAttributes();
        String src = (String) attributes.get(SRC);
 
        ResponseWriter responseWriter = context.getResponseWriter();
        responseWriter.endElement("div");
        responseWriter.write("<p><a href=\"wrapper.jsf?page=" + src + 
                             "\">[read on]</a></p>");
    }
}

The class Teaser extends UIComponentBase. The advantage of UIComponentBase compared to the alternative UIComponent is that it already implements some default behavior. There are only three methods we have to override. The abstrace method getFamily() is not implemented by UIComponentBase, so we must implement it ourselves. This method is supposed to return the category of the component. The category is important for choosing the correct renderer. For the simple teaser component we don't have to define a component category, so it simply returns null. The remaining two functions in the code above are more interesting. It is the methods that create the HTML to be rendered to the browser. HTML that should be rendered before the code enclosed by the custom component, is produced by encodeBegin(). HTML to put behind the code enclosed has to be generated by encodeEnd(). The HTML produced by these two methods is sent to the ResponseWriter of the FacesContext. In our example encodeBegin() opens the div tag, and encodeEnd() closes and generates the link.

To be able to use your component, you will have to configure it in the file WEB-INF/custom-taglib.xml. Basically you define the name of the tag for your component:

<?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/web-facelettaglibrary_2_0.xsd"
    version="2.0">
    <namespace>http://halboffen.at/ctlib</namespace>
    <tag>
        <tag-name>teaser</tag-name>
        <component>
            <component-type>
                at.halboffen.blog.jsf.component.Teaser
            </component-type>
        </component>
    </tag>
</facelet-taglib>

Finally you have to include your tag library in web.xml:

<web-app...>
...
    <context-param>
        <param-name>
            javax.faces.FACELETS_LIBRARIES
        </param-name>
        <param-value>
            /WEB-INF/custom-taglib.xml
        </param-value>
    </context-param>
...
</web-app>

That's it! Now you can include your component into your JSF webpages. Don't forget to define a namespace for your tag library:

<html xmlns:cc="http://halboffen.at/ctlib">
...
    <cc:teaser url="/posts/cleancode.xhtml" styleClass="teaser">
        <ui:include src="/posts/cleancode.xhtml" />
    </cc:teaser>
...
</html>

Get in touch