One of the major benefits of Java Server Faces (JSF) in comparison to other View frameworks is its easy extensibility. UI Components can be incorporated, custom converters and page-life-cycles can be defined and of course Validators can be developed an integrated into JSF applications. Although there is a number of tutorials and articles available on line on creating new custom Validators, they do not seem to discuss the creation of a validator that deals with more than one component(‘s value). For example I would like to have a Validator that enforces that one component can only have a value that is larger than the value of some other specified component.

Basically I want to be able to specify something like:

  &lt;af:inputText label=&quot;Old Salary&quot; id=&quot;oldSalary&quot;<br />                value=&quot;#{SalaryBean.oldSalary}&quot;/&gt;<br />  &lt;af:inputText label=&quot;New Salary&quot; value=&quot;#{SalaryBean.newSalary}&quot;<br />                id=&quot;newSalary&quot;&gt;<br />      &lt;AMISJSF:greaterThan greaterThanId=&quot;mainform:oldSalary&quot;/&gt;<br />  &lt;/af:inputText&gt;<br />          &nbsp;<br />

And have the validator raise an exception if the value in New Salary is lower than the value in Old Salary:

 

....
 

The steps for implementing this type of Custom Validator are fairly straightforward:

1. Create a class that implements the Validator interface 

2. Create a class for this Validator that extends the ValidatorTag class; this class supports a custom JSP tag for this validator (as opposed to using f:validator with validatorId)

3. Register the validator in the faces-config.xml

4. Create an entry for the validator tag in a tag-library

1. The Validator Class

The Validator Class looks like this:

package nl.amis.jsf.validator;<br /><br />import javax.faces.application.FacesMessage;<br />import javax.faces.component.EditableValueHolder;<br />import javax.faces.context.FacesContext;<br />import javax.faces.validator.Validator;<br />import javax.faces.validator.ValidatorException;<br />import javax.faces.component.UIComponent;<br /><br /><br />public class GreaterThanValidator implements Validator {<br /><br />    String greaterThanId;<br /><br />    public GreaterThanValidator() {<br />    }<br /><br />    public void validate(FacesContext facesContext, UIComponent uiComponent, <br />                         Object value) {<br />        if (null == value) {<br />            return;<br />        }<br />        UIComponent greaterThanComponent = <br />            uiComponent.findComponent(greaterThanId);<br />        if (greaterThanComponent != null) {<br />            if (greaterThanComponent instanceof EditableValueHolder) {<br />                Object greaterThanValue = <br />                    ((EditableValueHolder)greaterThanComponent).getValue();<br />                if (null == greaterThanValue) {<br />                    return;<br />                }<br />                if ((value instanceof Comparable) &amp;&amp; <br />                    (greaterThanValue instanceof Comparable)) {<br />                    if (((Comparable)value).compareTo((Comparable)greaterThanValue) &lt;  1 ) {<br />                        // raise exception as clearly value is not greater than greaterThanValue<br />                         FacesMessage message = new FacesMessage();<br />                         message.setDetail(&quot;Value in component &quot;+uiComponent.getClientId(facesContext)+&quot; (&quot;+value.toString()+&quot;) should be greater than &quot;+greaterThanValue.toString()+&quot;.&quot;);<br />                         message.setSummary(&quot;Value should be greater than &quot;+greaterThanValue.toString());<br />                         message.setSeverity(FacesMessage.SEVERITY_ERROR);<br />                         throw new ValidatorException(message);                    }<br />                }<br />            }<br />        }<br /><br /><br />    }<br />}<br />&nbsp;

The most noteworthy part is the part where the value of the ‘other’  component is retrieved.

2. The Validator Tag Class

The Tag Class to support a special custom tag for this validator is implemented as follows:

package nl.amis.jsf.tags;<br /><br />import javax.faces.validator.Validator;<br />import javax.faces.webapp.ValidatorTag;<br /><br />import javax.servlet.jsp.JspException;<br /><br />import nl.amis.jsf.validator.GreaterThanValidator;<br /><br />public class GreaterThanValidatorTag extends ValidatorTag{<br /><br />    String greaterThanId;<br /><br />    public GreaterThanValidatorTag() {<br />        setValidatorId(&quot;GreaterThan&quot;);<br />    }<br />    <br />    <br />   <br />    public Validator createValidator() throws JspException {<br />        GreaterThanValidator validator = (GreaterThanValidator) super.createValidator();<br />        validator.setGreaterThanId(greaterThanId);<br />    <br />        return validator;<br />    }<br />    <br />    public void release() {<br />        greaterThanId = null;<br />    }<br /><br />    public void setGreaterThanId(String greaterThanId) {<br />        this.greaterThanId = greaterThanId;<br />    }<br /><br />    public String getGreaterThanId() {<br />        return greaterThanId;<br />    }<br />}<br />&nbsp;

3. The entry in the custom tag library

The following entry is needed in the TLD for our Custom JSF Components Tag Library

  &lt;tag&gt;<br />    &lt;description&gt;Validator - Enforce that Component's value is GreaterThan other Component's Value&lt;/description&gt;<br />    &lt;display-name&gt;greaterThan&lt;/display-name&gt;<br />    &lt;name&gt;greaterThan&lt;/name&gt;<br />    &lt;tag-class&gt;nl.amis.jsf.tags.GreaterThanValidatorTag&lt;/tag-class&gt;<br />    &lt;attribute&gt;<br />      &lt;name&gt;greaterThanId&lt;/name&gt;<br />    &lt;/attribute&gt;<br />    &lt;body-content&gt;empty&lt;/body-content&gt;<br />    &lt;example&gt;Brief snippet showing how to use this tag.&lt;/example&gt;<br />  &lt;/tag&gt;&nbsp;<br />&nbsp;

4. Register validator in faces-config.xml

We need a simple entry in the faces-config.xml file to make the validator available to our application:

&lt;validator&gt;<br />    &lt;validator-id&gt;GreaterThan&lt;/validator-id&gt;<br />    &lt;validator-class&gt;nl.amis.jsf.validator.GreaterThanValidator&lt;/validator-class&gt;<br />&lt;/validator&gt;<br /><br />

Using the Custom Validator 

Using the custom validator in an application requires these steps

1. Add the lag-library (see step 4 above) to the ViewController project

 

This makes the validator available in the JSF components palette in the IDE I am working with:

2. Add the URI for the taglib to the JSPX page, making the tags available within the JSP JSF page

&lt;?xml version='1.0' encoding='UTF-8'?&gt;<br />&lt;jsp:root xmlns:jsp=&quot;http://java.sun.com/JSP/Page&quot; version=&quot;2.0&quot;<br />          xmlns:h=&quot;http://java.sun.com/jsf/html&quot;<br />          xmlns:f=&quot;http://java.sun.com/jsf/core&quot;<br />          xmlns:afh=&quot;http://xmlns.oracle.com/adf/faces/html&quot;<br />          xmlns:af=&quot;http://xmlns.oracle.com/adf/faces&quot;<br />          xmlns:AMISJSF=&quot;http://nl.amis.jsf/components&quot;&gt;<br />  &lt;jsp:output omit-xml-declaration=&quot;true&quot; doctype-root-element=&quot;HTML&quot;<br />&nbsp
;

3. Include the validator ta
g within a Input Component, such as InputText

            &lt;af:inputText label=&quot;Old Salary&quot; id=&quot;oldSalary&quot;<br />                          value=&quot;#{SalaryBean.oldSalary}&quot;/&gt;<br />            &lt;af:inputText label=&quot;New Salary&quot; value=&quot;#{SalaryBean.newSalary}&quot;<br />                          id=&quot;newSalary&quot;&gt;<br />              &lt;AMISJSF:greaterThan greaterThanId=&quot;mainform:oldSalary&quot;/&gt;<br />            &lt;/af:inputText&gt;<br /><br />

Here we see two inputText elements, oldSalary and newSalary, both inside a form called mainform. The newSalary element has been subjected to the custom validator greatherThan through the AMISJSF:greaterThan tag. We have specified the greatherThanId attribute; it refers to mainform:oldSalary, the clientId of the Old Salary element. This will enforce our rule that the New Salary must be greater than the old salary. 

The component-tree for our page looks as follows:

 

 

Now we can run the application. 

 

Submitting these values will raise no error as the validation rule is not violated. However submitting a form with values 4000 for Old Salary and 1200 for New Salary will raise an exception:

 

Resources

 

Excellent tutorial on creating a Custom Validator (my main inspiration for this article): Java Server Faces FAQ How to create the custom validator?