JSF: Custom Validation Tag Example
Sep 27, 2014
1. Validation in JSF
JavaServer Faces technology supports a mechanism for validating the local data of editable components (such as text fields). This validation occurs before the model data is updated to match the local value.
The validation model defines a set of standard classes for performing common data validation checks. The JSF core tag library defines a set of tags that correspond to the standard validator implementations.
JSF allows you to create your own custom validator to perform validation. There are two ways to implement validation code: (a) Implement Validator interface, or (b) Implement a managed bean method.
If you are implementing a Validator interface, you must: (a) Register the Validator implementation with the application, and (b) create a custom tag or use the core f:validator
tag to use the validator on a component.
This post is about creating a custom validator and using it with its own tag. The example validation field is a phone number with ten digits in a specified format.
2. Usage Example
In some countries, users are familiar with entering phone numbers in a certain format. The format can be one of "9999999999", "999 999 9999" or "999-999-9999".
In a web page the formatting and separators for the phone number are specified by the page author. A custom validator is used to validate the phone number and its format.
The validator is used with its own tag. The tag has one optional attribute - formats. The tag's attribute specifies the valid phone number formats. The usage of formats attribute:
- The attribute value can be a string literal with comma (",") separated format values, or an EL value expression that resolves to the formats string.
- In case no attribute is specified, or all invalid formats are specified, the default format "999999999" is used.
- All invalid formats are ignored, when specified with other valid formats.
Depending on the requirement, the page author can specify one or more formats in a page. This allows the user to enter the phone number in any of the specified formats.
The validator checks the formats, the number of digits in phone number and other validation criteria.
The following code snippets explain a usage example, validator implementation and its configuration. See note at the bottom of the page to access complete source code for the example:
3. Usage Example JSF Page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:app="http://jsfapp.com"/>
...
<h:outputLabel for="phoneNo"
value="Enter phone number with format as 9999999999 or 999-999-9999:"/>
<h:inputText id="phoneNo" value="#{requestScope.phone}"
required="true" label="Phone Number">
<app:validatePhone formats="#{bean.formats}" />
</h:inputText>
...
The custom validator tag's namespace is declared as: xmlns:app="http://jsfapp.com"
. This tag is used as <app:validatePhone formats="#{bean.formats}" />
. Note, for the formats attribute instead of an EL Value Expression, a string can be specified like this:
<app:validatePhone formats="999999999,999-999-999" />
The formats attribute value is declared in a bean, as shown in the following code snippet:
4. Formats Bean
@ManagedBean(name="bean")
public class FormatsBean {
private String formats= "999-999-9999,999999999";
public String getFormats() {
return formats;
}
...
5. Custom Validator Implementation
The custom validator implements javax.faces.validator.Validator
interface and overrides it's validate()
method.
The validator stores all the valid formats in a Map
collection. The map's key is the format name, and value is the format string.
The formats attribute specified by the page author, in the usage example, is read and validated against the valid ones in the map. The setFormats()
method reads the custom tag attribute value specified in the page.
If the user enters the phone number with a wrong format - the formats not specified by the attribute value - an exception is thrown and a message is displayed.
The following snippet shows some sections of the validator's code:
@FacesValidator("app.phoneValidator")
public class PhoneValidator implements Validator {
// all valid formats
private static Map<String, String> formatMap = new HashMap<>();
static {
formatMap.put("default", "9999999999");
formatMap.put("hyphen-separated", "999-999-9999");
formatMap.put("space-separated", "999 999 9999");
}
// exception message strings
private static String summaryMsg = "Invalid phone numer.";
private static String detailMsg =
"The phone number is not valid. Please verify the format and enter again.";
// attribute values specified in the validator tag, and the setter method
private String formats;
public void setFormats(String s) {
formats = s;
}
@Override
public void validate(FacesContext context, UIComponent component,
Object inputValue)
throws ValidatorException {
// get and validate formats attribute values
// in case of no valid formats, the default format is used
List<String> verifiedFormats = verifyAttributeFormats();
// validate data
String value = (String) inputValue;
...
// validate the input value against each valid format specified in
// the attribute and when a format match happens exit the loop
// check for the number for digits, and other criteria
FormatsLoop:
for (String format : verifiedFormats) {
switch (format) {
case "default":
stringNo = value;
if (stringNo.length() == 10) {
valid = true;
break FormatsLoop;
}
break;
...
} // end FormatsLoop
if (valid) {
try {
number = new Long(stringNo);
}
catch (NumberFormatException nfe) {
valid = false;
}
}
if (! valid) {
FacesMessage msg = new FacesMessage(summaryMsg, detailMsg);
throw new ValidatorException(msg);
}
} // validate()
...
}
6. Configuration
The following snippets show the tag library descriptor and its location in the deployment descriptor. Note that there are no entries in the application resource configuration file (not shown here).
6.1. Tag Library Descriptor: app.taglib.xml
<facelet-taglib ... >
<namespace>http://jsfapp.com</namespace>
<tag>
<tag-name>validatePhone</tag-name>
<validator>
<validator-id>app.phoneValidator</validator-id>
</validator>
</tag>
</facelet-taglib>
Note that the validator-id
specifies the custom validator implementation's identifier (not the class name). The tag-name
and the namespace
are used in the usage page.
6.2. Deployment Descriptor: web.xml
Include the following entry in the web.xml file. The param-value
specifies the location of the tag library descriptor.
<context-param>
<param-name>javax.faces.FACELETS_LIBRARIES</param-name>
<param-value>/WEB-INF/app.taglib.xml</param-value>
</context-param>
7. JSF Coding
JavaServer Faces version 2.0 is used to develop this example. The code has been tested on Tomcat 6 using Apache MyFaces 2.0 and on GlassFish 3 application server (GlassFish 3 implements Java EE 6).
7.1. Source Code
(a) Usage page index.xhtml
, (b) the managed bean that specifies the format attributes FormatsBean.java
, (c) the custom validator implementation PhoneValidator.java
, (d) the tag library descriptor for the custom validator tag app.taglib.xml
, and (e) the deployment descriptor specifying the location of the tag library web.xml
, and (f) an empty application configuration file faces-config.xml
(g) the web application WAR file contents, and (h) the web application screenshot. Click this link to view the source code.
7.2. Download
Download source code here: JSFValidatorExample.zip
8. Useful Links
- Apache MyFaces 2.0: http://myfaces.apache.org/core20/index.html
- GlassFish 3 documentaion: https://glassfish.java.net/downloads/v3-final.html
- JSF 2.0 specification: https://jcp.org/aboutJava/communityprocess/final/jsr314/