How to create a custom JSF Validator – The Greater Than Validator to enforce one component's value being larger than some other's

4

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?

 

 

 

Share.

About Author

Lucas Jellema, active in IT (and with Oracle) since 1994. Oracle ACE Director for Fusion Middleware. Consultant, trainer and instructor on diverse areas including Oracle Database (SQL & PLSQL), Service Oriented Architecture, BPM, ADF, Java in various shapes and forms and many other things. Author of the Oracle Press book: Oracle SOA Suite 11g Handbook. Frequent presenter on conferences such as JavaOne, Oracle OpenWorld, ODTUG Kaleidoscope, Devoxx and OBUG. Presenter for Oracle University Celebrity specials.

4 Comments

  1. The validator needs to implement StateHolder. See javax.faces.validator.DoubleRangeValidator for implementation details.

  2. Hi Lucas,
    Thanks for the reply and i had checked the application for the items u have specified ,din’t find any thing missing out there by me
    In GreaterThanValidatorTag which extends ValidatorTag
    public void setGreaterThanId(String greaterThanId) {
    this.greaterThanId = greaterThanId;
    }

    public String getGreaterThanId() {
    return greaterThanId;
    }
    public void release() {
    greaterThanId = null;
    }
    for setting greaterThanId

    In MyTag.tld

    Validator – Enforce that Component’s value is GreaterThan other Component’s Value
    greaterThan
    greaterThan
    view.frameworkExt.jsf.tags.GreaterThanValidatorTag

    greaterThanId

    empty
    Brief snippet showing how to use this tag.

    and in Jsf Jsp page only

    where form is provided with id “form1″

    please comment any thing need to be configured more to use this Custom Validations effectively

  3. Hi Ravi,

    My first hunch would be that in the GreaterThanValidatorTag class you have not implemented the setter method in the correct way. However, perhaps even more likely is that you have not defined the attribute greaterThanId to the Tag Library Description.

    Did you specify the value of the greaterThanId correctly in the JSP JSF page? You are not by any chance using the validator in a table component ?

    Lucas

  4. I had incorparated this Validation in my application , but only Client side validation is working fine and if correct(valid) values are provided then it is Throwing Null pointer Exception at the line jsf.validator.GreaterThanValidator.validate(GreaterThanValidator.java:25) ie at
    UIComponent greaterThanComponent =
    uiComponent.findComponent(greaterThanId);

    on debuging the code i found that “greaterThanId” is passed as null in the GreaterThanValidator class Object
    need to know any mistake done by me as i tested the sample application too which is working fine

    any help please

    thanks in advance.
    Ravi