Jul 1, 2015

Creating custom JSF components or widgets library

If you are using JSF you can easily move some parts of your code and widgets/components into external library. Here I will describe how to do in quick and correct way.

In this particular example I will show you how to create your own JSF converters library, but you can use this approach to make any other JSF libraries. You can see complete example of working JSF library here https://github.com/javaplugs/jsf-plugs

The main steps in developing JSF library are:
  1. Do some coding for your components, converters etc.
  2. Add JSF files required for custom components (will not describe this step here)
  3. Create faces-confg.xml
  4. Create your.taglib.xml
  5. Create your.tld file
Now let explain it in details.

JSF converter implementation

First of all we should implement at least one JSF converter.
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

public class MyConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        // Will not describe converter implementation here
        // You should convert here value to particular object
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        // Will not describe converter implementation here
        // You should convert here particular object to string representation
        throw new UnsupportedOperationException("Not supported yet.");
    }
}
Any code will not be accessible from  JSF library until you will add some "enty points" to faces-confg.xml

Registering your code in faces-confg.xml

In your project resources you should create META-INF/faces-confg.xml Only in this case faces-confg.xml will be scanned by JSF environment from your library.
<?xml version='1.0' encoding='UTF-8'?>
<faces-config
    version="2.0"
    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-facesconfig_2_0.xsd">

    <name>Your Library Name</name>
    
    <converter>
        <converter-id>converter.Name</converter-id>
        <converter-class>path.to.MyConverter</converter-class>
    </converter>
</faces-config>
Now you will be able to use your converter in JSF pages. Note that any JSF related java code should be registered in faces-confg.xml This is most appropriate way to make it accessible for your JSF environment.
<h:inputText value="#{jsfBean.data}">
   <f:converter converterId="converter.Name" />
</h:inputText>

Creating JSF taglib.xml

If you want to create complete JSF tag for component or converter you should add taglib.xml file to your project. Taglib file must be located in META-INF folder and file name must be yourname.taglib.xml (*.taglib.xml). Important part is that file suffix must be always .taglib.xml
<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
    version="2.0"
    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">
    <!-- Can be any even non existend URL -->
    <!-- it is just an identifier -->
    <namespace>https://github.com/javaplugs/jsf-plugs</namespace>
    <tag>
        <tag-name>myConverter</tag-name>
        <converter>
            <converter-id>converter.Name</converter-id>
        </converter>
        <attribute>
            <name>format</name>
        </attribute>
    </tag>
</facelet-taglib>
As you can see here, there is an attribute tag. This tag allows you to pass additional attributes to your converter. Mind that you must implement appropriate getters and setters first.

After creating taglib.xml you will be able to add your tags in JSF pages and use them
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
   xmlns:f="http://java.sun.com/jsf/core"    
   xmlns:h="http://java.sun.com/jsf/html"
   xmlns:you="https://github.com/javaplugs/jsf-plugs"
   xmlns:ui="http://java.sun.com/jsf/facelets">
   <h:body>
      <h2>Converter Test</h2>
      <hr />
      <h:inputText id="urlInput" value="#{userData.data}" label="URL" >
        <you:myConverter format="some_fomat_value" />
      </h:inputText>    
   </h:body>
</html>
Here you can see attribute xmlns:you="https://github.com/javaplugs/jsf-plugs" It means that now all your tags defined in .taglib.xml with URI identifier https://github.com/javaplugs/jsf-plugs will be available under namespace "you". Note that you should add your own getters and setters for attribute format.

Creating your.tld file

If you want to have auto completion for your tags in IDE or you just want that your IDE will treat your custom tags as valid, than you should create additional *.tld file. This file must be located at META-INF directory. Better to name it as your taglib, for example if you have mytags.taglib.xml you should create mytags.tld.

For our particular example tld file content will be next
<?xml version="1.0" encoding="UTF-8"?>
<taglib 
    ersion="2.0" 
    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-jsptaglibrary_2_0.xsd">
    <tlib-version>2.0</tlib-version>
    <short-name>you</short-name>
    <uri>https://github.com/javaplugs/jsf-plugs</uri>

    <tag>
        <name>myConverter</name>
        <description>Whatewer</description>
        <tag-class>package.of.MyConverter</tag-class>
        <body-content>JSP</body-content>
        <attribute>
            <name>formatter</name>
            <required>false</required>
            <rtexprvalue>false</rtexprvalue>
            <deferred-value>
                <type>java.lang.String</type>
            </deferred-value>
        </attribute>
    </tag>
</taglib>
As you can see here we are using the same URI identifier from taglib, but here we are using direct class names over JSF identifiers. Short-name tag just describes preferred xml namespace name (xmlns:you in our case).

And that is all folks. Now your Java class will be accessible as  JSF converter, you will be able add it to your page from your custom library of by using converterId="converter.Name" attribute, and your tag library will be IDE friendly.

Note that all stuff related to .taglib.xml and .tld can be used not only with JSF, but also with well known JSP.