JSF - Creating a Custom Converter Tag

[Updated: Sep 10, 2017, Created: Sep 10, 2017]

This tutorial demonstrates how to create a custom converter tag. With the custom tag, we can specify attributes as well which will map to the converter class properties.

Example

The Converter

@FacesConverter("phConverter")
public class PhoneConverter implements Converter {
  private String format;

  @Override
  public Object getAsObject(FacesContext context, UIComponent component, String value) {
      Phone phone = PhoneFormat.parse(format, value);
      return phone;
  }

  @Override
  public String getAsString(FacesContext context, UIComponent component, Object value) {
      Phone phone = (Phone) value;
      return PhoneFormat.format(format, phone);
  }

  public String getFormat() {
      return format;
  }

  public void setFormat(String format) {
      this.format = format;
  }
}
public enum PhoneFormat {
  STANDARD("(\\d{3})-(\\d{3})-(\\d{4})") {
      @Override
      String format(Phone phone) {
          return phone.getAreaCode() +
                  "-" + phone.getExchangeCode() +
                  "-" + phone.getLineNumber();
      }
  },
  PLAIN("(\\d{3})(\\d{3})(\\d{4})") {
      @Override
      String format(Phone phone) {
          return phone.getAreaCode() +
                  phone.getExchangeCode() +
                  phone.getLineNumber();
      }
  };

  private final Pattern compiledPattern;

  PhoneFormat(String pattern) {
      compiledPattern = Pattern.compile(pattern);
  }

  public static PhoneFormat getPhoneFormat(String formatString) {
      try {
          return valueOf(formatString.toUpperCase());
      } catch (IllegalArgumentException | NullPointerException e) {
          //returning default format;
          return STANDARD;
      }
  }

  public static Phone parse(String formatString, String value) {
      PhoneFormat phoneFormat = getPhoneFormat(formatString);
      Matcher matcher = phoneFormat.compiledPattern.matcher(value);
      if (!matcher.matches()) {
          throw new RuntimeException(
                  String.format("invalid input: %s. The valid format is of type %s%n",
                          value, phoneFormat.compiledPattern.pattern()));
      }
      String areaCode = matcher.group(1);
      String exchange = matcher.group(2);
      String line = matcher.group(3);
      return new Phone(areaCode, exchange, line);
  }

  public static String format(String formatString, Phone phone) {
      PhoneFormat phoneFormat = getPhoneFormat(formatString);
      return phoneFormat.format(phone);
  }

  abstract String format(Phone phone);
}
public class Phone {
  private String areaCode;
  private String exchangeCode;
  private String lineNumber;
    .............
}

Creating the custom tag

src\main\webapp\WEB-INF\mylib.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/ui</namespace>

    <tag>
        <tag-name>phoneConverter</tag-name>
        <converter>
            <converter-id>phConverter</converter-id>
        </converter>
        <attribute>
            <name>format</name>
            <type>java.lang.String</type>
        </attribute>
    </tag>
</facelet-taglib>

Registering the tag

src\main\webapp\WEB-INF\web.xml

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

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

</web-app>

JSF page

src/main/webapp/index.xhtml

<?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:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:u="http://example.com/ui">
<h:head></h:head>
<h:body>
    <h2>JSF custom converter example</h2>
    <h:form>
        <h:panelGrid columns="2">

            <h:outputLabel for="wph" value="Work Phone: "/>
            <h:inputText id="wph" value="#{phoneBean.workPhone}">
                <u:phoneConverter format="standard"/>
            </h:inputText>

            <h:outputLabel for="cph" value="Cell Phone: "/>
            <h:inputText id="cph" value="#{phoneBean.cellPhone}">
                <u:phoneConverter format="plain"/>
            </h:inputText>

            <h:commandButton value="Submit" action="result.xhtml"/>
        </h:panelGrid>
        <div>
            work Phone:
            <h:outputText value = "#{phoneBean.workPhone}">
                <!--the default format will be used-->
                <u:phoneConverter />
            </h:outputText>
        </div>
        <div>
            Cell Phone:
            <!--no formatting will be used-->
            <h:outputText value = "#{phoneBean.cellPhone}"/>
        </div>
    </h:form>
</h:body>
</html>

Managed Bean

@ManagedBean
@ViewScoped
public class PhoneBean {
  private Phone workPhone;
  private Phone cellPhone;

  public Phone getWorkPhone() {
      return workPhone;
  }

  public void setWorkPhone(Phone phone) {
      this.workPhone = phone;
  }

  public Phone getCellPhone() {
      return cellPhone;
  }

  public void setCellPhone(Phone cellPhone) {
      this.cellPhone = cellPhone;
  }
}

To try examples, run embedded tomcat (configured in pom.xml of example project below):

mvn tomcat7:run-war

Output

On entering and submitting valid phone numbers:

Example Project

Dependencies and Technologies Used :

  • jsf-api 2.2.14: This is the master POM file for Oracle's Implementation of the JSF 2.2 Specification. .
  • jsf-impl 2.2.14: This is the master POM file for Oracle's Implementation of the JSF 2.2 Specification. .
  • JDK 1.8
  • Maven 3.3.9

JSF Custom Converter Tag Example Select All Download
  • custom-converter-tag
    • src
      • main
        • java
          • com
            • logicbig
              • example
        • webapp
          • WEB-INF

See Also