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:
<af:inputText label="Old Salary" id="oldSalary"
value="#{SalaryBean.oldSalary}"/>
<af:inputText label="New Salary" value="#{SalaryBean.newSalary}"
id="newSalary">
<AMISJSF:greaterThan greaterThanId="mainform:oldSalary"/>
</af:inputText>
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;
import javax.faces.application.FacesMessage;
import javax.faces.component.EditableValueHolder;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
import javax.faces.component.UIComponent;
public class GreaterThanValidator implements Validator {
String greaterThanId;
public GreaterThanValidator() {
}
public void validate(FacesContext facesContext, UIComponent uiComponent,
Object value) {
if (null == value) {
return;
}
UIComponent greaterThanComponent =
uiComponent.findComponent(greaterThanId);
if (greaterThanComponent != null) {
if (greaterThanComponent instanceof EditableValueHolder) {
Object greaterThanValue =
((EditableValueHolder)greaterThanComponent).getValue();
if (null == greaterThanValue) {
return;
}
if ((value instanceof Comparable) &&
(greaterThanValue instanceof Comparable)) {
if (((Comparable)value).compareTo((Comparable)greaterThanValue) < 1 ) {
// raise exception as clearly value is not greater than greaterThanValue
FacesMessage message = new FacesMessage();
message.setDetail("Value in component "+uiComponent.getClientId(facesContext)+" ("+value.toString()+") should be greater than "+greaterThanValue.toString()+".");
message.setSummary("Value should be greater than "+greaterThanValue.toString());
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message); }
}
}
}
}
}
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;
import javax.faces.validator.Validator;
import javax.faces.webapp.ValidatorTag;
import javax.servlet.jsp.JspException;
import nl.amis.jsf.validator.GreaterThanValidator;
public class GreaterThanValidatorTag extends ValidatorTag{
String greaterThanId;
public GreaterThanValidatorTag() {
setValidatorId("GreaterThan");
}
public Validator createValidator() throws JspException {
GreaterThanValidator validator = (GreaterThanValidator) super.createValidator();
validator.setGreaterThanId(greaterThanId);
return validator;
}
public void release() {
greaterThanId = null;
}
public void setGreaterThanId(String greaterThanId) {
this.greaterThanId = greaterThanId;
}
public String getGreaterThanId() {
return greaterThanId;
}
}
3. The entry in the custom tag library
The following entry is needed in the TLD for our Custom JSF Components Tag Library
<tag>
<description>Validator - Enforce that Component's value is GreaterThan other Component's Value</description>
<display-name>greaterThan</display-name>
<name>greaterThan</name>
<tag-class>nl.amis.jsf.tags.GreaterThanValidatorTag</tag-class>
<attribute>
<name>greaterThanId</name>
</attribute>
<body-content>empty</body-content>
<example>Brief snippet showing how to use this tag.</example>
</tag>
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:
<validator>
<validator-id>GreaterThan</validator-id>
<validator-class>nl.amis.jsf.validator.GreaterThanValidator</validator-class>
</validator>
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
<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:afh="http://xmlns.oracle.com/adf/faces/html"
xmlns:af="http://xmlns.oracle.com/adf/faces"
xmlns:AMISJSF="http://nl.amis.jsf/components">
<jsp:output omit-xml-declaration="true" doctype-root-element="HTML"
  ;
3. Include the validator ta
g within a Input Component, such as InputText
<af:inputText label="Old Salary" id="oldSalary"
value="#{SalaryBean.oldSalary}"/>
<af:inputText label="New Salary" value="#{SalaryBean.newSalary}"
id="newSalary">
<AMISJSF:greaterThan greaterThanId="mainform:oldSalary"/>
</af:inputText>
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?
The validator needs to implement StateHolder. See javax.faces.validator.DoubleRangeValidator for implementation details.
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
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
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