Simple Java based JSF 2.2 custom component

11 May 2013, by: Arjan Tijms

In JSF components play a central role, it being a component based framework after all.

As mentioned in a previous blog posting, creating custom components was a lot of effort in JSF 1.x, but became significantly easier in JSF 2.0.

Nevertheless, there were a few tedious things left that needed to be done if the component was needed to be used on a Facelet (which is the overwhelmingly common case); having a -taglib.xml file where a tag for the component is declared, and when the component’s Java code resides directly in a web project (as opposed to a jar) an entry in web.xml to point to the -taglib.xml file.

In JSF 2.2 these two tedious things are not needed anymore as the Facelets component tag can be declared using the existing @FacesComponent annotation.

As an update to the original blog posting, a simple Java based custom component can be created as follows:

components/CustomComponent.java

@FacesComponent(value = "components.CustomComponent", createTag = true)
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());
        }
    }
}

This is all there is to it. The above fully defines a Java based JSF custom component. There is not a single extra registration and not a single XML file needed to use this on a Facelet, e.g.

page.xhtml

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

Just these two files (and only these two files) fully constitute a Java EE/JSF application. The .java file does need to be compiled to a .class of course, but then just these two can be deployed to a Java EE 7 server. There’s not a single extra (XML) file, manifest, lib, or whatever else needed as shown in the image below:

custom_component_deploy

Using GlassFish 4.0 b88, requesting http://localhost:8080/customcomponent/page.jsf will simply result in a page displaying:

TEST

So can this be made any simpler? Well, maybe there’s still some room for improvement. What about the getFamily method that still needs to be implemented? It would be great if that too could be defaulted to something. Likewise, the component name could be defaulted to something as well, and while we’re at it, let’s give createTag a default value of true in case the component name is defaulted (only in that case such as not to cause backwards compatibility issues).

Another improvement would be if component attributes could be declared JPA-style via annotations. That way tools can learn about their existence and the code could become a tiny but simpler. E.g.

@FacesComponent
public class CustomComponent extends UIComponentBase {
 
    @Attribute
    String value;
 
    @Override
    public void encodeBegin(FacesContext context) throws IOException { 
        if (value != null) {        
            ResponseWriter writer = context.getResponseWriter();
            writer.write(value.toUpperCase());
        }
    }
}

The above version is not reality yet, but the version at the beginning of this article is and that one is really pretty simple already.


Arjan Tijms

4 comments to “Simple Java based JSF 2.2 custom component”

  1. Anonymous says:

    In your xhtml page, you have xmlns:test=”http://xmlns.jcp.org/jsf/component”. Where is this namespace being defined?

  2. Arjan Tijms says:

    In your xhtml page, you have xmlns:test=”http://xmlns.jcp.org/jsf/component”. Where is this namespace being defined?

    The namespace is not being defined at all. It’s the default namespace where components are put in if you don’t define one explicitly. You can override this if you want on theh FacesComponent annotation.

  3. Damon says:

    Hi,

    I followed your example and it worked fine but if I move the custom component Java class into a separate jar file it stops working. It doesn’t find the component and just leaves the custom tag unexpanded in the html.

    Any idea what I need to do to fix this?

    Thanks, Damon

  4. Damon says:

    I should mention I’m running this under jetty using the maven plugin.

    It works when the class is in WEB-INF/classes but not when it is inside a jar in WEB-INF/lib

Type your comment below:

best counter