Using Bean Validation (JSR 303) annotations with Apache MyFaces 1.2

Exclusive offer: get 50% off this eBook here
Apache MyFaces 1.2 Web Application Development

Apache MyFaces 1.2 Web Application Development — Save 50%

Building next-generation web applications with JSF and Facelets

£16.99    £8.50
by Bart Kummel | March 2010 | Java Open Source Web Development

This article by Bart Kummel, author of Apache MyFaces 1.2 Web Application Development, shows how we can use Bean Validation (JSR 303) annotations to declaratively define validation rules in our Java EE application. In this article, Apache MyFaces Extensions Validator (ExtVal) is used to generate the JSF validators, based on Bean Validation annotations. While JSF 2.0 has native support for Bean Validation, ExtVal can also be used with JSF 1.2. And ExtVal offers some possibilities that cannot be achieved with the default JSF 2.0 Bean Validation support.

This article is the third in a series of ExtVal articles. Other articles in this series:

Using annotations in JavaBeans is an elegant way of defining validation rules in a declarative way. Apart from MyFaces ExtVal there are other projects that introduced declarative validation, such as the Hibernate Validator and the Bean Validation Framework for Spring. Some framework developers realized that it would be a good idea to standardize this type of validation. This led to the Bean Validation specification that was developed as JSR 303 in the Java Community Process. Accordingly, Bean Validation will be a standard part of Java EE 6, but it can be used in Java EE 5 by manually including a Bean Validation implementation.

One of the benefits of having an official standard for validation is that various user interface frameworks can implement support for this type of validation. For example, JavaServer Faces 2.0 will have support for Bean Validation embedded in it, and other UI frameworks will probably follow

But at the moment, we’re still building Java EE 5 and JSF 1.2 applications. And although we can use Bean Validation in Java EE 5, JSF 1.2 doesn’t have Bean Validation support. And that’s where ExtVal comes in. We can use ExtVal to integrate JSR 303 Bean Validation into JSF 1.2 (and even JSF 1.1) projects. This section will discuss some Bean Validation basics and show how to use Bean Validation with ExtVal.

Note that we can only cover some basics of Bean Validation here. As Bean Validation is a new standard, there is not much reference documentation available yet. However, some decent documentation comes bundled with Hibernate Validator—the reference implementation of JSR 303. That documentation is also available online at http://docs.jboss.org/hibernate/stable/validator/reference/. As an alternative, the official specification of JSR 303 can be used as documentation. The official specification can be found at http://jcp.org/en/jsr/summary?id=303.

Setting up Bean Validation and ExtVal

To use Bean Validation, we need a JSR 303 implementation, unless we’re using a Java EE 6 compliant application server. Currently, the only available JSR 303 implementation is the reference implementation, which is Hibernate Validator 4.0. Hibernate Validator can be downloaded from http://www.hibernate.org/subprojects/validator/download.html . We should make sure we download a 4.0 version, as versions before 4.0 do not implement the JSR 303 standard. At the time of writing this article, the latest release is 4.0.2 GA.

After downloading Hibernate Validator, we have to add the Bean Validation libraries to our project. All libraries have to be in the shared lib directory of our EAR. We also have to add the libraries that Hibernate Validator depends on. The following table shows a list of libraries that have to be added to our project in order to be able to use the Hibernate Validator. If we had used Maven, these libraries would have been downloaded and added to our project automatically by Maven.


Library

Description

Where to get

hibernate-validator-4.0.2.GA.jar

The main Hibernate Validator library.

Included in the root directory of the Hibernate Validator distribution.

validation-api-1.0.0.GA.jar

Contains all interfaces and annotations defined by the JSR 303 standard.

Included in the lib directory of the Hibernate Validator distribution.

slf4j-log4j12-1.5.6.jar

slf4j-api-1.5.6.jar

log4j-1.2.14.jar

jpa-api-2.0.Beta-20090815.jar

 

Runtime dependencies of Hibernate Validator.

Included in the lib directory of the Hibernate Validator distribution.

activation-1.1.jar

jaxb-api-2.1.jar

jaxb-impl-2.1.3.jar

stax-api-1.0-2.jar

Runtime dependencies for Hibernate Validator. These libraries are only needed if we run Hibernate Validator on a JDK 5 version. So even if we use a Java EE 5 server that runs on a JDK 6, we don't need these libs.

Included in the lib/jdk5 directory of the Hibernate Validator distribution.

Once we have added the Bean Validation libraries to our project, we have to make sure that we have also added ExtVal’s Bean Validation module to our project. The Bean Validation module is only available from ExtVal version 1.2.3 onwards. See the Setting up ExtVal section for more details.

Using Bean Validation annotations

The basic usage of Bean Validation is very similar to the use of ExtVal’s Property Validation annotations. There are some differences in the annotations, though. The following table lists all of the annotations that are defined in the Bean Validation specification:


Annotation

Attributes

Description

@AssertFalse

 

Assure that the element that is annotated is false.

@AssertTrue

 

Assure that the element that is annotated is true.

@DecimalMin

value

The value of the annotated element must be a numeric value greater than or equal to the indicated value. The value attribute must be a String that will be interpreted as a BigDecimal string representation.

@DecimalMax

value

The value of the annotated element must be a numeric value less than or equal to the indicated value. The value attribute has the same behavior as the value attribute of the @DecimalMin annotation.

@Digits

integer, fraction

The annotated element must have a numeric value that can't have more integer digits and fraction digits than indicated by the integer and fraction attributes.

@Past

 

Can be applied to java.util.Date and java.util.Calendar elements. The value of the annotated element must be in the past.

@Future

 

Can be applied to java.util.Date and java.util.Calendar elements. The value of the annotated element must be in the future.

@Min

value

Only for integer values. The value of the annotated element must be greater than or equal to the given value.

@Max

value

Only for integer values. The value of the annotated element must be less than or equal to the given value.

@NotNull

 

The annotated value can't be null.

@Null

 

The annotated value must be null.

@Pattern

regexp, flags

Can only be applied to Strings. The annotated String must match the regular expression that is given in the regexp attribute. The flags attribute can be set to an array of Pattern.Flag values, indicating which flags should be set to the java.util.regex.Pattern that will be used to match the value against. Valid flags are UNIX_LINES, CASE_INSENSITIVE, COMMENTS, MULTILINE, DOTALL, UNICODE_CASE, and CANON_EQ. See the JavaDoc documentation of java.util.regex.Pattern for an explanation of the flags. (http://java.sun.com/javase/6/docs/api/java/util/regex/Pattern.html)

@Size

min, max

Can be applied to Strings, Collections, Maps, and arrays. Verifies that the size of the annotated element is between the given min and max values, min and max included.

@Valid

 

For recursive validation.

All annotations are defined in the javax.validation.constraints package. Apart from the attributes mentioned in the previous table, all annotations (except the @Valid annotation) have the following common attributes:

  • message: This attribute can be used to set a custom error message that will be displayed if the constraint defined by the annotation is not met. If we want to set a message bundle key instead of a literal message, we should surround it with braces. So we can set message to either "This value is not valid" or "{inc.monsters.mias.not_valid}".
  • groups: This attribute can be used to associate a constraint with one or more validation processing groups. Validation processing groups can be used to influence the order in which constraints get validated, or to validate a bean only partially. (See http://docs.jboss.org/hibernate/stable/validator/reference/en/html/validator-usingvalidator.html#validator-usingvalidator-validationgroups for more on validation groups.)
  • payload: This attribute can be used to attach extra meta information to a constraint. The Bean Validation standard does not define any standard metadata that can be used, but specific libraries can define their own metadata. This mechanism can be used with ExtVal to add severity information to constraints, enabling the JSF pages to show certain constraint violations as warnings instead of errors. See the Using payloads to set severity levels section for an example of this.

OK, now we know which annotations can be used. Let’s see how we can use Bean Validation annotations on our Employee class:

// Package declaration and imports omitted for brevity

public class Employee implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;


@Temporal(TemporalType.DATE)
@Column(name="BIRTH_DATE")
@Past
private Date birthDate;

@Column(name="FIRST_NAME")
private String firstName;

@Temporal(TemporalType.DATE)

@Column(name="HIRE_DATE")
@Past
private Date hireDate;

@Column(name="JOB_TITLE")
@NotNull
@Size(min=1)
private String jobTitle;

@Column(name="LAST_NAME")

private String lastName;

@Min(value=100)
private int salary;
@Column(name="KIDS_SCARED")
private int kidsScared;

@OneToMany(mappedBy="employee")

private List<Kid> kids;

// Getters and setters and other code omitted.
}

The Bean Validation annotations are highlighted in the code example. Note that the annotations are applied to the member variables here. Alternatively, we could have applied them to the getter methods. In this example, the birthDate and hireDate are annotated with @Past so that only dates in the past can be set. The jobTitle is set to have a minimum length of one character by the @Size annotation. The salary must have a minimum value of 100, as set by the @Min annotatiion.

Reusing validation

Bean Validation does not have a solution like the @JoinValidation annotation of ExtVal’s Property Validation module. However, Bean Validation offers other ways to avoid repetitive code and help us reusing validation. This section describes some of the possibilities

Inheriting validation

Constraints defined on (the properties of) super classes are inherited. This means that if we have a super class called Person, like the following example, our Employee class can inherit the properties—including the annotated constraints—as follows:

public class Person {
@Size(min=1)
private String firstName;

@Size(min=1)

private String lastName;

@Past
private Date birthDate;

// Getters and setters omitted.
}

No special actions have to be taken to inherit annotated validation constraints.

Using recursive validation

We can use the @Valid annotation to use recursive validation (or graph validation as it is called in the JSR 303 specification). The @Valid annotation can be used on single member objects as well as on Collections. If applied to a Collection, all objects in the collection are validated, but null values in the Collection are ignored. For example, we could use this to validate the List of scared Kids that is part of our Employee class, as follows:

public class Employee implements Serializable {

// Other member variables are left out here.


@OneToMany(mappedBy="employee")
@Valid
private List<Kid> kids;

// Getters and setters are omitted.
}

Now the List of Kids that is referenced by the kidsvariable can only contain valid Kid objects. This means that all Bean Validation constraints that are defined on the Kid class will be checked on all Kid objects in the List.

Apache MyFaces 1.2 Web Application Development Building next-generation web applications with JSF and Facelets
Published: March 2010
eBook Price: £16.99
Book Price: £27.99
See more
Select your format and quantity:

Composing custom constraints

A third way to prevent the repetition of code is to define constraint compositions. Compared to ExtVal’s @JoinValidation, defining a custom constraint can be used in at least as many situations as @JoinValidation . Defining custom constraints with Bean Validation gives a more structural solution, compared to using @JoinValidation. However, defining a custom constraint might involve a bit more work than using @JoinValidation

Another difference between constraint compositions and @JoinValidation is that constraint compositions can only be used to compose constraints out of other JSR 303 constraints, whereas @JoinValidation can also be used to combine constraints from different types, such as combining JPA constraints with ExtVal Property Valdiation constraints. So all-in-all, @JoinValidation and constraint composition have some overlap, but both also have their own unique features.

Defining a custom constraint involves creating a new annotation. This may look a bit complicated at first, but it is less complicated than it seems. Let’s see how we can create an @Name annotation that we can use on all names in our project:

package inc.monsters.mias.data.validation;


import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.OverridesAttribute;
import java.lang.annotation.Retention;

import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@NotNull
@Size(min = 2)


@Constraint(validatedBy = {})
@Retention(RUNTIME)
@Target({METHOD, FIELD, ANNOTATION_TYPE})
public @interface Name {


String message() default "{inc.monsters.mias.data.validation.Name.invalid_name}";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};


@OverridesAttribute(constraint = Size.class, name = "max")
int maxLength() default 20;

}

In this example, the following interesting things can be observed:

  • public @interface Name: This defines a new annotation—@Name.
  • @Target: This defines on what elements the new @Name annotation can be used. In this case, it can be used on methods, fields, and other annotations. Most of the time, this is fine for new constraints. It is also possible to create constraints that validate a class; in that case, TYPE should be used as the target. (See http://docs.jboss.org/hibernate/stable/validator/reference/en/html/validator-usingvalidator.html#d0e328 for more information on class-level constraints.)
  • @Retention: This defines that this annotation should be executed at runtime. For validation constraints, this should always be set to RUNTIME.
  • @Constraint: This identifies this annotation as being a validation constraint. It should always be used for custom constraints.
  • @NotNull and @Size(min=2) (right above the @Constraint annotation, highlighted): These are the constraints that the @Name constraint is based on. In other words, any element annotated with @Name must not be null and must have a size of at least 2.
  • int maxLength() default 20: This defines an attribute maxLength for the @Name annotation, with a default value of 20. So if no maxLength is specified, the maxLength will be 20.
  • @OverridesAttribute(constraint = Size.class, name = "max"): This causes the maxLength attribute to override the max attribute of the Size annotation.
  • String message() default "{...}": This sets the default value of the message attribute to a message bundle key.

Other code that is not mentioned in the bulleted list is needed for every constraint definition. We now have an @Name annotation that can be used on any name field in our project. The annotated field cannot be empty, and should have a size of at least 2, and at most 20. The maximum size can be overridden by the maxLength attribute. We can use it, for example, in our Employee class, as follows

public class Employee implements Serializable {

// Other member variable are omitted.


@Column(name="FIRST_NAME")
@Name
private String firstName;

@Column(name="LAST_NAME")
@Name(maxLength = 40)
private String lastName;

// Getters and setters are omitted.

}

Now, the firstName can’t be null. It must have at least 2 characters and at most 20 characters. The lastName has the same constraints, but can be up to 40 characters long. Creating our own custom constraint may be a little more work, but it gives us a more structural way of reuse. And we don’t get referencing problems, as we did with @JoinValidation. As a bonus, we can reuse custom constraints over different projects. We can even create a library of custom constraints to be used in several projects.

As an example of the flexibility and extendability of ExtVal, the next section will show us how we can set severity levels on certain constraints that give the users the possibility to ignore certain warnings.

Using payloads to set severity levels

As mentioned, we can use the payload attribute on every Bean Validation annotation to pass on meta information about the constraint. With ExtVal, we can use this to create warning messages for certain constraints. These warning messages will appear the first time the user submits a value that violates the constraint. The user can either change the value or ignore the warning by submitting the value for the second time. This section describes how we can implement this for the salary field of our Employee class.

Setting up the Continue with warnings add-on

Let’s start by downloading and installing the Continue with warnings add-on, as described in the Extending ExtVal with add-ons section. Once we’ve downloaded the JAR file and added it to our project, we can start preparing our project to allow the users to ignore warnings. The first thing we’ll have to do is to add a hidden input component to all pages where we expect warnings to be shown that the user should be able to ignore. In our example, we only have to add this hidden component to our EditEmployee.xhtml page, as we will only be adding a warning-level constraint to our Employee entity. The following code snippet shows the hidden component added to the EditEmployee.xhtml page:

<ui:composition template="templates/template.xhtml">
<ui:define name="title">Edit employee</ui:define>
<ui:define name="content">

<h:inputHidden id="extValWarnState" value="#{extValWarnState.continueWithWarnings}"/>
<tr:panelFormLayout>
<!-- Form contents left out to save space. -->
</tr:panelFormLayout>

</ui:define>
</ui:composition>

The <h:inputHidden> component provides the Continue with warnings add-on with a way to remember if the warning has already been shown to the user, and if the user has already clicked on the submit button. It is important to not change the id and value of the component, as the add-on expects them to have the values that we just saw.

In our example, we add the hidden input component to only one page. In a real-world application, the chances are that we need this component on (nearly) every page. It may seem a good idea to add the hidden component to our page template. However, this will cause the “warning state” to be shared by all pages, which will cause undesired behavior. So, unfortunately, we’ll have to add the hidden component to every page. On a side note, the requirement to use a hidden input is a design decision that was made when the add-on was created. Of course, the open source nature of the project allows us to alter this behavior of the add-on if we like.

Setting the severity level of a constraint

Once we have added the hidden input component to the pages where warnings can be shown, we can set the severity level of one of our constraints to “warning”. Let’s see how we can do this for the salary variable in the Employee class

package inc.monsters.mias.data;

import org.apache.myfaces.extensions.validator.beanval.payload.ViolationSeverity;

// Other imports are hidden for brevity.


public class Employee implements Serializable {

@Min(value=100, payload=ViolationSeverity.Warn.class)
private int salary;

// All other variables and methods are omitted.
}

The only thing we added here is the payload=ViolationSeverity.Warn.class attribute of the @Min annotation. And, of course, we had to add an import for the ViolotionSeverity class.

Now, if we run our application and put a value below 100 in the salary input field on the “Edit employee” page, a warning will be shown on submitting the form. However, if we submit the form with the same value for the second time, the warning will disappear and the data will be saved regardless of the violation of the @Min constraint. This allows the manager that uses the “Edit Employee” page to override the “no salaries below 100” policy.

Setting the severity level is not limited to Bean Validation constraints. Although setting a severity level is introduced in the Using Bean Validation section, setting a severity level is also possible with ExtVal’s own Property Validation annotations, and even with other constraints such as constraints based on JPA annotations. This will be discussed in the following two sections.

Setting the severity level on ExtVal Property Validation constraints

To set a severity level to an ExtVal Property Validation annotation, we should use the parameters attribute of the annotation instead of payload. We should also import another ValidationSeverity class. If we had used ExtVal annotations instead of JSR 303 annotations in our Employee class, the salary variable declaration would now look like this:

package inc.monsters.mias.data;

import org.apache.myfaces.extensions.validator.core.validation.parameter.ViolationSeverity;


// Other imports are hidden for brevity.

public class Employee implements Serializable {


@LongRange(minimum=100, parameters=ViolationSeverity.Warn.class)
private int salary;

// All other variables and methods are omitted.
}

Notice the changed import (the first highlighted part of the snippet) and the ExtVal @LongRange annotation that replaces the @Min annotation from the JSR 303 example.

The use of the parameters attribute in this example is just a convention. Unlike the payload attribute in the Bean Validation example, the attributes of ExtVal annotations are not fi xed. ExtVal scans all of the attributes of its annotations by type. This means that any parameter with the ViolationSeverity.Warn type—or any other type implementing the ValidationParameter interface—will be interpreted as metadata by ExtVal.

Setting the severity level on any constraint

Although the Bean Validation annotations, as well as the ExtVal annotations, have special attributes that can be used to add metadata such as the severity level, other annotations that are used to defi ne constraints may not have such facilities. For these cases, we can use the Virtual Meta Data add-on , which is a part of the Advanced Meta Data add-on bundle. See the Extending ExtVal with add-ons section for download and installation instructions for this add-on.

The only other constraint type that is currently supported out of the box by ExtVal is the JPA constraint. As JPA constraints are derived from database constraints, it doesn’t make sense to bypass the violation of such constraints. So, by default, ExtVal will not allow this even if we set the severity level to warning. However, we can set the severity level to “fatal” to be able to mark error messages from JPA constraints as more important than other error messages that are marked with level “error” by default. This does make more sense as an example in this case.

The next example shows the lastName variable, annotated with the JPA @Column annotation with its nullable attribute set to false. This effectively makes the lastName variable a required field. To mark the violation of this constraint as more important than other violations, we want to set the severity level to “fatal”. As the @Column annotation does not have an attribute to set extra metadata, we use the @VirtualMetaData annotation from the add-on to set the metadata as follows:

package inc.monsters.mias.data;


import org.apache.myfaces.extensions.validator.core.validation.parameter.ViolationSeverity;


// Other imports are hidden for brevity.

public class Employee implements Serializable {

@Column(nullable=false)

@VirtualMetaData(target=Column.class, parameters=ViolationSeverity.Fatal.class)
private String lastName;

// All other variables and methods are omitted.
}

Note that the attributes of the @VirtualMetaData annotation accept exactly the same types as the attributes of all ExtVal Property Validation annotations. That’s why we can use the same ValdationSeverity class in this case. The target attribute is needed to link the @VirtualMetaData annotation to the @Column annotation.

Summary

This article showed us how we can integrate ExtVal with JSR 303 Bean Validation.

This article is the third in a series of ExtVal articles. Other articles in this series:

Apache MyFaces 1.2 Web Application Development Building next-generation web applications with JSF and Facelets
Published: March 2010
eBook Price: £16.99
Book Price: £27.99
See more
Select your format and quantity:

About the Author :


Bart Kummel

Bart Kummel is an experienced Java EE developer and architect living in The Netherlands. He studied Electrical Engineering at the Delft University of Technology and graduated with honor from the Hogeschool van Amsterdam, with a specialization in Technical Computer Sciences. After his study, he started as a developer of embedded software for a security systems manufacturer in Amsterdam. After four years of developing embedded software, Bart switched to enterprise software and started at Transfer Solutions B.V., based in Leerdam. Transfer Solutions is a consulting company that specializes in Oracle and Java technology.

As a consultant for Transfer Solutions, Bart gained a lot of experience with Java EE. For different clients, he has fulfilled the roles of developer or architect in small as well as large projects. In those projects, he has worked with various frameworks and standards, including Oracle’s Application Development Framework (ADF), Apache MyFaces, EclipseLink, JavaServer Faces (JSF), Java Persistence API (JPA), and Java Messaging Service (JMS). Bart also teaches courses in Object Orientation, UML, Java, Java EE, and ADF, at Transfer Solutions’ education department.

Bart published an article on EclipseLink in the Dutch Java Magazine, and presented the use of AJAX capabilities in Oracle’s ADF Faces at the ODTUG Kaleidoscope conference in 2007.

The link to his website is www.bartkummel.net

Books From Packt


Zen Cart: E-commerce Application Development
Zen Cart: E-commerce Application Development

Drupal E-commerce with Ubercart 2.x
Drupal E-commerce with Ubercart 2.x

Alfresco Enterprise Content Management Implementation
Alfresco Enterprise Content Management Implementation

jBPM Developer Guide
jBPM Developer Guide

jQuery 1.4 Reference Guide
jQuery 1.4 Reference Guide

AJAX and PHP: Building Modern Web Applications 2nd Edition
AJAX and PHP: Building Modern Web Applications 2nd Edition

Drupal 6 Attachment Views
Drupal 6 Attachment Views

Magento 1.3: PHP Developer's Guide
Magento 1.3: PHP Developer's Guide


Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software