JSF : Validators

JavaServer Faces technology supports a mechanism for validating the data of editable components. Validation is 3rd phase in life cycle. Each component in JavaServer Faces, created Error Messages during the life cycle of JSF and attached them to FacesContext object. Hence each message is attached to a component in the component tree and the message is displayed into the view at the end of JSF life cycle.

JSF supports both Declarative and Imperative means of validations

1.Declarative

  • Using JSF standard validators
  • Using Bean validation — JSR 303

2. Imperative

  • Validation Method in backing bean
  • Custom validator by implementing javax.faces.validator.Validator and annotating the class with @FacesValidator or validator tag in faces-config.xml

SF provides different tags to handle and display messages on the view. There are two message tags in Sun’s reference implementation of JSF HTML library:

  • <h:message />
  • <h:messages />

h:message is used to display message attached to one component. An attibute for=”” can be used to specify the id of a component whose error messages we need to display. h:message is used to display error message next to the component that generated the error. If more then one message is attached to that component, h:message will display the last message.

<h:inputText label=”Name” value=”#{validatorDeclarativeBeanAndAction.name}” id=”name” required=”true”>
<h:message for=”name” />
h:messages is used to display all messages at once, also the ones which are already displayed in a h:message in the page. You can place h:messages tag in start of your form. You may need to display only global messages using h:messages tag. When the value of the globalOnly attribute is true, only global messages (i.e. messages without a client Id) will be displayed; when the value is false, global messages will be displayed in addition to other messages that are already queued. By default globalOnly  is false.
Each message can have a summary description and a detailed description. When using the h:message tag, the default is to show the detail message. When using the h:messages tag, the default is to display the summary descriptions. To change the defaults, modify the booleanshowSummary and showDetail attributes.
<h:message for=”name” showSummary=”true”/>
<h:messages showDetail=”true”/>
Lets see this by an example. ValidatorDeclarativeBeanAndAction.java
package mynotes.jsf.bean;import javax.faces.bean.ManagedBean;

@ManagedBean(name="validatorDeclarativeBeanAndAction")
public class ValidatorDeclarativeBeanAndAction {

private String name;
private String age;

public String submit(){
System.out.println("In Submit");
System.out.println("name=>"+name);
System.out.println("age=>"+age);
return "validatorDeclarative";
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}

}

validatorDeclarative.xhtml
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Validator Declarative</title>
</head>
<h:body>
<h3>Validator Declarative</h3>
<h:form>
<table>
<tr>
<td><h:outputLabel for="id" value="Name: "></h:outputLabel></td>
<td><h:inputText label="Name"
value="#{validatorDeclarativeBeanAndAction.name}" id="name"
required="true"></h:inputText> <h:message for="name" /></td>
</tr>
<tr>
<td><h:outputLabel for="age" value="Age: "></h:outputLabel></td>
<td><h:inputText label="Age"
value="#{validatorDeclarativeBeanAndAction.age}" id="age"
required="true">
<f:validateLongRange minimum="18" maximum="50" />
</h:inputText> <h:message for="age" /></td>
</tr>
<tr>
<td colspan="2"><h:commandButton value="Submit"
action="#{validatorDeclarativeBeanAndAction.submit}"></h:commandButton></td>
</tr>
</table>
</h:form>
</h:body>
</html>
The above code will check for valid values of the “name” and “age” field. Notice the ‘label’ attribute in the h:inputText. This is what jsf will take while displaying the error message for a componenet id. If not mentioned , the defalut label will be formid+componentid, which may be not user friendly. Other attributes like required=true and <f:validateLongRange> are self explanatory.  There are many such tags. In order to customize your messages, you need to add a message bundle element to your faces-config.xml.
<application>
<message-bundle>mynotes.jsf.properties.ValidatorProperteis</message-bundle>
</application>
ValidatorProperteis.properties
javax.faces.validator.LongRangeValidator.MAXIMUM={1}: Value is greater than allowable maximum of ''{0}''
javax.faces.validator.LongRangeValidator.MINIMUM={1}: Value is less than allowable minimum of ''{0}''
javax.faces.validator.LengthValidator.MAXIMUM={1}: Value is greater than allowable maximum of ''{0}''
javax.faces.validator.LengthValidator.MINIMUM={1}: Value is less than allowable minimum of ''{0}''
javax.faces.component.UIInput.REQUIRED={0} is a mandatory field
javax.faces.validator.LongRangeValidator.NOT_IN_RANGE={2}: Field needs to be between the expected values of {0} and {1}
validatorDeclarative
Till now we have seen Declarative Validation using JSF tags. Lets now see Declarative Validation using Bean Validation.
The Bean Validation JSR (JSR-303) defines a generic, tier-independent mechanism for specifying data validation constraints. The specification includes several standard constraint annotations (eg. @NotNull, @Size, @Min, @Max,@Pattern etc…) and also allows custom constraints to be defined. JSF 2 provides built-in integration with JSR-303 constraints. When you are using bean validation in your application, JSF automatically uses the constraints for beans that are referenced by UIInput values.
Changing ValidatorDeclarativeBeanAndAction.java
package mynotes.jsf.bean;

import javax.faces.bean.ManagedBean;
import javax.validation.constraints.Size;

@ManagedBean(name="validatorDeclarativeBeanAndAction")

public class ValidatorDeclarativeBeanAndAction {

@Size(min = 5, max=20, message = "Please enter a valid username (5-20 characters)")
private String name;
//rest all same
.
Notice the import, javax.validation.constraints. For this package you have to import an implementation, I have used hibernate-validator version 5.  Add the following dependency to your pom.xml
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.1.Final</version>
</dependency>
By default, the Bean Validator is enabled, therefore our JSF pages do not need to contain any info about the Bean Validator. When validation constraints fail, any associated error messages are automatically translated into FacesMessages by the JSF implementation.You can however disable the validator for any field of the ManagedBean
<h:inputText label="Name"
value="#{validatorDeclarativeBeanAndAction.name}" id="name"
required="true">
<f:validateBean disabled="true" />
</h:inputText>

Custom validation components using Validator interface

Steps

  • Create a validator class by implements javax.faces.validator.Validator interface.
  • Override validate() method.
  • Assign an unique validator ID via @FacesValidator annotation or <validator> tag in faces-config.xml
  • Reference custom validator class to JSF component via f:validator tag.

Lets write an email validator. EmailValidator.java


package mynotes.jsf.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

@FacesValidator("emailValidator")
public class EmailValidator implements Validator {

private static final String EMAIL_REGEXP = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";

public void validate(FacesContext arg0, UIComponent arg1, Object val)
throws ValidatorException {
String email = (String) val;
Pattern mask = null;
mask = Pattern.compile(EMAIL_REGEXP);
Matcher matcher = mask.matcher(email);

if (!matcher.matches()) {
FacesMessage message = new FacesMessage();
message.setDetail("Please enter a valid email [from validator interface]");
message.setSummary("Email not valid [from Validator interface]");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}

}

}

Validation using Backing Bean methods

A backing bean method can be used for doing validation of any input field. First we need to create the backing bean method that will get called during validation process. The signature of the method has to be like the validate method we overrrided previously.

Adding a validator method in backing bean. ValidatorCustomBeanAndAction.java


package mynotes.jsf.bean;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;

@ManagedBean(name = "validatorCustomBeanAndAction")
public class ValidatorCustomBeanAndAction {

private String primaryEmail;
private String seconfryEmail;

public String submit() {
System.out.println("In Submit");
System.out.println("primaryEmail=>" + primaryEmail);
System.out.println("seconfryEmail=>" + seconfryEmail);
return "validatorCustom";
}

public void validateEmailFromBean(FacesContext arg0, UIComponent arg1, Object val)
throws ValidatorException {
String EMAIL_REGEXP = "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";
String email = (String) val;
Pattern mask = null;
mask = Pattern.compile(EMAIL_REGEXP);
Matcher matcher = mask.matcher(email);

if (!matcher.matches()) {
FacesMessage message = new FacesMessage();
message.setDetail("Please enter a valid email [from validator bean]");
message.setSummary("Email not valid [from Validator bean]");
message.setSeverity(FacesMessage.SEVERITY_ERROR);
throw new ValidatorException(message);
}

}

public String getPrimaryEmail() {
return primaryEmail;
}

public void setPrimaryEmail(String primaryEmail) {
this.primaryEmail = primaryEmail;
}

public String getSeconfryEmail() {
return seconfryEmail;
}

public void setSeconfryEmail(String seconfryEmail) {
this.seconfryEmail = seconfryEmail;
}

}

validatorCustom.xhtml


<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<title>Validator Custom</title>
</head>
<h:body>
<h3>Validator Custom</h3>
<h:form>
<table>
<tr>
<td><h:outputLabel for="primary_email" value="Primary Email: "></h:outputLabel></td>
<td><h:inputText label="Primary Email"
value="#{validatorCustomBeanAndAction.primaryEmail}" id="primary_email"
required="true">
<f:validator validatorId="emailValidator"/>
</h:inputText> <h:message for="primary_email" style="color:red" /></td>
</tr>
<tr>
<td><h:outputLabel for="secondry_email" value="Secondry Email: "></h:outputLabel></td>
<td><h:inputText label="Secondry Email"
value="#{validatorCustomBeanAndAction.seconfryEmail}" id="secondry_email"
required="true" validator="#{validatorCustomBeanAndAction.validateEmailFromBean}">

</h:inputText> <h:message for="secondry_email" style="color:red" /></td>
</tr>
<tr>
<td colspan="2"><h:commandButton value="Submit"
action="#{validatorCustomBeanAndAction.submit}"></h:commandButton></td>
</tr>
</table>
</h:form>
</h:body>
</html>

Notice that the primary email validation points to the interface implementation using <f:validator> tag, whereas secondry email validation is dont using the validator attribute in the inputText field.

validatorCustom

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: