Probably the most important validation tag provided by JSF 2.0 is the f:validateBean
tag. For a start, you have to know that this tag is part of a mechanism whose aim is to integrate Bean Validation with JSF 2.0. Bean Validation—known as JSR 303 (http://jcp.org/en/jsr/detail?id=303); officially part of the new Java EE 6 this defines a metadata model and API for JavaBean validation. The default "metadata source is annotations, with the ability to override and extend the meta-data through the use of XML validation descriptors". In this recipe, you will see how to exploit the Bean Validation.
We developed this recipe with NetBeans 6.8, JSF 2.0, and GlassFish v3. The JSF 2.0 classes were obtained from the NetBeans JSF 2.0 bundled library.
Instead of placing validation rules in different layers of the application and keeping them synchronized, we can take use of Bean Validation and use its constraint annotations in the managed beans—JSF 2 provides built-in integration with JSR-303 constraints—as in the following example:
public class userBean { @NotEmpty(message = "The name cannot be empty!") @Size(min = 5, max = 20, message="You must provide a name between 5 and 20 characters!") private String name; @Digits(integer = 2, fraction = 0, message = "You must provide a valid age!") @Range(min=18, max=99, message="You must be over 18 years old!") private int age; @NotEmpty(message = "The email cannot be empty!") //instead of @Pattern you can use @Email @Pattern(regexp = "[a-zA-Z0-9_]*[@]{1}[a-zA-Z0-9_]*[.]{1}[a-zA-Z]{2,3}", message="You must provide at least an well-formed e-mail address!") private String email; …
In the following table you can see a summary of the Bean Validation annotation with a short description:
Annotation |
BVS * |
Apply on |
Use |
---|---|---|---|
|
Yes |
Field/property |
Check that the annotated element is |
|
Yes |
Field/property |
Check that the annotated element is |
|
Yes |
Field/property Supported types are:
|
Check that the annotated element is a number whose value is lower than or equal to the specified maximum. |
|
Yes |
Field/property Supported types are:
|
Check that the annotated element is a number whose value is higher than or equal to the specified minmum. |
|
Yes |
Field/property Supported types are:
|
Check that the annotated element is a number having up to |
|
Yes |
Field/property Supported types are |
Check that the annotated date is in the future. |
|
Yes |
Field/property Supported types are:
|
Check that the annotated value is less than or equal to the specified maximum. |
|
Yes |
Field/property Supported types are:
|
Check that the annotated value is higher than or equal to the specified minimum. |
|
Yes |
Field/property |
Check that the annotated value is not null. |
|
Yes |
Field/property |
Check that the annotated value is null. |
|
Yes |
Field/property |
Perform validation recursively on the associated object. |
|
Yes |
Field/property Supported types are |
Check that the annotated date is in the past. |
|
Yes |
field/property Supported types are |
Check if the annotated element size is between |
|
No |
Field/property |
Check that the annotated string is between |
|
No |
Field/property |
Check that the annotated string is not null or empty. |
|
No |
Field/property |
Check that the annotated string is a valid email address. |
|
No |
Field/property Supported types are:
|
Check that the annotated value lies between the specified minimum and maximum (inclusive). |
* BVS - Bean Validation Specification
The annotations marked as "yes" belong to BVS and they can be found in the javax.validation.constraints
package, while the ones marked with "no" can be found in the org.hibernate.validator.constraints
package.
After we set our annotation, we can control (fine tune) the validation from the JSF pages with the f:validateBean
tag. The f:validateBean
supports the following optional attributes:
binding
: A ValueExpression
that evaluates to an object that implements javax.faces.validate.BeanValidator
.disabled
: A boolean value enabling page-level determination of whether or not this validator is enabled on the enclosing component.validationGroups
: A comma-delimited string of type-safe validation groups that are passed to the Bean Validation API when validating the value.… <h:form> <h:panelGrid columns="2"> <h:outputText value="Name:"/> <h:inputText value="#{userBean.name}"/> <h:outputText value="Age:"/> <h:inputText value="#{userBean.age}"/> <h:outputText value="E-mail:"/> <h:inputText value="#{userBean.email}"/> </h:panelGrid> <h:commandButton value="Submit" action="index?faces- redirect=true"/> </h:form> …
A possible output is in the following screenshot:
Now, if we want to disable the Bean Validator for a specific field, then we must get involved and set the disabled
attribute to false
, as in the following code, where we disable validation for the user age:
… <h:outputText value="Age:"/> <h:inputText value="#{userBean.age}"> <f:validateBean disabled="true" /> </h:inputText> …
Add a context-param
to your web.xml, javax.faces.VALIDATE_EMPTY_FIELDS
, by default it is set to auto
. If it is true
, all submitted fields will be validated. This is necessary to delegate validation of whether a field can be null/empty to the model validator. If it is false
, empty values will not be passed to the validators. If it is auto
, the default will be true
only if Bean Validation is in the environment, false
otherwise (which keeps backward compatibility).
You also may want to save the validation groups—allowing you to restrict the set of constraints applied during validation—in an attribute on the parent to be used as defaults inherited by any Bean Validator in that context (an empty String
is not allowed). If no validation groups are inherited, assume the Default
validation group, javax.validation.groups.Default
.
The property validationGroups
on BeanValidator is used to allow the view designer to specify a comma-separated list of groups that should be validated. A group is represented by the fully qualified class name of its interface. If the validationGroups
attribute is omitted, the Default
(javax.validation.groups.Default) group will be used. If the model validator is set as the default validator, this tag can be used to specify validation groups for this input.
In practice, groups are just simple Java interfaces. Using interfaces makes the usage of groups type safe and allows for easy refactoring. In addition, groups can inherit from each other via class inheritance. As per the example, we can use two different groups as shown next:
//the usersIdsGroup public interface usersIdsGroup { } //the usersCredentialsGroup public interface usersCredentialsGroup { }
Next, we can bind managed beans' properties to groups as shown next:
… @NotEmpty(message = "The name cannot be empty!", groups = beans.usersIdsGroup.class) @Size(min = 5, max = 20, message = "You must provide a name between 5 and 20 characters!", groups = beans.usersIdsGroup.class) private String name; @Digits(integer = 2, fraction = 0, message = "You must provide a valid age!", groups = beans.usersIdsGroup.class) @Range(min = 18, max = 99, message = "You must be over 18 years old!", groups = beans.usersIdsGroup.class) private int age; @NotEmpty(message = "The email cannot be empty!", groups = beans.usersIdsGroup.class) //instead of @Pattern you can use @Email @Pattern( regexp = "[a-zA-Z0-9_]*[@]{1}[a-zA-Z0-9_]*[.]{1}[a-zA-Z]{2,3}", message = "You must provide at least an well-formed e-mail address!", groups = beans.usersIdsGroup.class) private String email; @NotEmpty(message = "The ID cannot be empty!", groups = beans.usersCredentialsGroup.class) @Size(min = 5, max = 20, message = "You must provide an ID between 5 and 20 characters!", groups = beans.usersCredentialsGroup.class) private String nickname; @NotEmpty(message = "The password cannot be empty!", groups = beans.usersCredentialsGroup.class) @Size(min = 5, max = 20, message = "You must provide a password between 5 and 20 characters!", groups = beans.usersCredentialsGroup.class) private String password; …
As you can see, the name, age
, and email
properties belong to the usersIdsGroup
group, while the nickname
and password
properties belongs to the usersCredentialsGroup
group. Next, in a JSF page, we can validate both groups like this:
… <f:validateBean validationGroups="beans.usersIdsGroup,usersCredentialsGroup"> <h:outputText value="Name:"/> <h:inputText value="#{userBean.name}"/> <h:outputText value="Age:"/> <h:inputText value="#{userBean.age}"/> <h:outputText value="E-mail:"/> <h:inputText value="#{userBean.email}"/> <h:outputText value="ID:"/> <h:inputText value="#{userBean.nickname}"/> <h:outputText value="Password"/> <h:inputSecret value="#{userBean.password}"/> </f:validateBean> …
If we want to validate only the usersIdsGroup
group, then we remove this group from the value of the validationGroups
attribute:
… <f:validateBean validationGroups="beans.usersIdsGroup"> … </f:validateBean> …
You also may call a Bean validator programatically. The following code snippet shows you how to accomplish this:
public class UserValidator { public boolean validateUser(userBean user) { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); Set<ConstraintViolation<userBean>> constraintViolations = validator.validate(user, Default.class); if (!constraintViolations.isEmpty()) return false; constraintViolations = validator.validate(user, beans.usersIdsGroup.class); return constraintViolations.isEmpty(); } }
As you just saw, Bean Validation centralized constraint declarations and is based on a several standard constraint annotations (for example @Size, @Min, @Max, @AssertTrue, @AssertFalse
, and so on) and also allows custom constraints to be defined. In addition we can use groups that allow us to restrict the set of constraints applied during validation. This time the validator restrictions are taken directly from the bean, instead of using dedicated attributes inside the validator tag.
The complete reference for Bean Validation is JSR-303 available at http://jcp.org/en/jsr/detail?id=303.
The code bundled with this book contains a complete example of this recipe. The project can be opened with NetBeans 6.8 and it is named: Bean_validation_with_validateBean_1
and Bean_validation_with_validateBean_2
.
More details about the f:validateBean
tag specification can be found at:
https://javaserverfaces.dev.java.net/nonav/docs/2.0/pdldocs/facelets/f/validateBean.html