Simple Java based JSF 2.2 custom component

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:

Using Payara 4.x, 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

Comments

Popular posts from this blog

Implementing container authentication in Java EE with JASPIC

Jakarta EE Survey 2022

Counting the rows returned from a JPA query