Home > Java > Bean validation and JSR 303

Bean validation and JSR 303

In this article, I will show you how to use the new Bean Validation Framework aka JSR-303.

The legacy

Before getting the result that is JSR 303, aka the Bean Validation framework, there were two interesting attempts at validation framework. Each came from an end of the layers and focused on its scope.

Front-end validation

Struts was the framework to learn and use on the presentation layer in 2001-2002. Struts uses the MVC model and focus on Controllers, which are represented in Struts with Action.  Views are plain JSP and Struts uses ActionForm in order to pass data from Controllers to Views and vice-versa. In short, those are POJO that the framework uses to interact with the View.

As a presentation layer framework, Struts concern is validating user input. Action forms have a nifty method called validate(). The signature of this method is the following:

public ActionErrors validate(ActionMapping mapping, HttpServletRequest request)

The developer has to check whether the form is valid then fill the ActionErrors object (basically a List) if it’s not the case. Struts then redirects the flow to an error page (the input) if the ActionErrors object is not empty. Since manual checking is boring and error-prone, it may be a good idea to automate such validation. Even at that time, declarative validation was considered to be the thing.

This is the objective of Apache Commons Validator. Its configuration is made through XML. You specify:

  • the validators you have access to. There are some built-in but you can add your own
  • the associations between beans and validators: which beans will be validated by which rules

Though Struts tightly integrates Commons Validator, you can use the latter entirely separately. However, the last stable version (1.3.1) was released late 2006. The current developed version is 1.4 but the Maven site hasn’t been updated since early 2008. It is a bit left aside for my own tatse so I rule it out for my validation needs save when I am forced to use Struts.

In this case it is mandatory for me to use it since the Struts plugin knows how to use both XML configuration files to also produce JavaScript client-side validation.

Back-end validation

Previously, we saw that the first validation framework came from user input. At the other end of the specter, inserting/updating data does not require such validation since constraints are enforced in the database. For example, trying to insert a 50 characters length string into a VARCHAR(20) column will fail.

However, letting the database handle validation has two main drawbacks:

  • it has a performance cost since you need to connect to the database, send the request and handle the error
  • such error cannot be easily mapped to a Java exception and if possible, to a particular attribute in error

In the end, it is better to validate the domain model in the Java world, before sending data to the database. Such was the scope of Hibernate Validator. Whereas Commons Validator configuration is based on XML, Hibernate Validator is based on Java 5 annotations.

Even if Hibernate Validator was designed to validate the domain model, you could use it to validate any bean.

JSR 303 Bean Validation

Finally, JSR 303 came to fruitition. Two important facts: it is end-agnostic, meaning you can use it anywhere you like (front-end, back-end, even DTO if you follow this pattern) and its reference implementation is Hibernate Validator v4.

JSR 303 features include:

  • validation on two different levels: attribute or entire bean. That was not possible with Hibernate Validator (since it was database oriented) and only possible with much limitations with Commons Validator
  • i18n ready and message are parameterized
  • extensible with your own validators
  • configurable with annotations or XML. In the following, only the annotation configuration will be shown

In JSR 303, validation is the result of the interaction between:

  • the annotation itself. Some come with JSR 303, but you can build your own
  • the class that will validate the annotated bean

Simplest example

The simplest example possible consist of setting a not-null constraint on an attribute of a class. This is done simply so:

public class Person {

  private String firstName;

  @NotNull
  public String getFirstName() {

    return firstName;
  }

  // setter
}

Note that the @NotNull annotation can be placed on the attribute or on the getter (just like in JPA). If you use Hibernate, it can also use your JSR 303 annotations in order to create/update the database schema.

Now, in order to validate an instance of this bean, all you have to do is:

Set<ConstraintViolation<Person>> violations = validator.validate(person);

If the set is empty, the validation succeeded, it not, it failed: the principle is very similar to both previous frameworks.

Interestingly enough, the specs enforce that constraints be inherited. So, if a User class inherits from Person, its firstName attribute will have a not-null constraint too.

Constraints groups

On the presentation tier, it may happen that you have to use the same form bean in two different contexts, such as create and update. In both contexts you have different constraints. For example, when creating your profile, the username is mandatory. When updating, it cannot be changed so there’s no need to validate it.

Struts (and its faithful ally Commons Validator) solve this problem by associating the validation rules not with the Java class but with the mapping since its scope is the front-end. This is not possible when using annotations. In order to ease bean reuse, JSR 303 introduce constraint grouping. If you do not specify anything, like previously, your constraint is assigned to the default group, and, when validating, you do so in the default group.

You can also specify groups on a constraint like so:

public class Person {

  private String firstName;

  @NotNull(groups = DummyGroup)
  public String getFirstName() {

    return firstName;
  }

  // setter
}

So, this will validate:

Person person = new Person();

// Empty set
Set<Constraintviolation<Person>> violations = validator.validate(person);

This will also:

Person person = new Person();

// Empty set
Set<Constraintviolation<Person>> violations = validator.validate(person, Default.class);

And this won’t:

Person person = new Person();

// Size 1 set
Set<Constraintviolation<Person>> violations = validator.validate(person, DummyGroup.class);

Custom constraint

When done playing with the built-in constraints (and the Hibernate extensions), you will probably need to develop your own. It is very easy: constraints are annotations that are themselves annotated with @Constraint. Let’s create a constraint that check for uncapitalized strings:

@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CapitalizedValidator.class)
public @interface Capitalized {

  String message() default "{ch.frankel.blog.validation.constraints.capitalized}";

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

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

The 3 elements are respectively for internationalization, grouping (see above) and passing meta-data. These are all mandatory: if not defined, the framework will not work! It is also possible to add more elements, for example to parameterize the validation: the @Min and @Max constraints use this.

Notice there’s nothing that prevents constraints from being applied to instances rather than attributes, this is defined by the @Target and is a design choice.

Next comes the validation class. It must implement ConstraintValidator<?,?>:

public class CapitalizedValidator implements ConstraintValidator<Capitalized, String> {

  public void initialize(Capitalized capitalized) {} 

  public boolean isValid(String value, ConstraintValidatorContext context) {

    return value == null || value.equals(WordUtils.capitalizeFully(value));
  }
}

That’s all! All you have to do now is annotate attributes with @Capitalized and validate instances with the framework. There’s no need to register the freshly created validator.

Constraints composition

It is encouraged to create simple constraints then compose them to create more complex validation rules. In order to do that, create a new constraint and annotate it with the constraints you want to compose. Let’s create a constraint that will validate that a String is neither null nor uncapitalized:

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

  String message() default "{ch.frankel.blog.validation.constraints.capitalized}";

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

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

Now, annotate your attributes with it and watch the magic happen!

Of course, if you want to prevent constraint composition, you’ll have to restrain the @Target values to exclude ANNOTATION_TYPE.

Conclusion

This article only brushed the surface of JSR 303. Nevertheless, I hoped it was a nice introduction to its features and gave you the desire to look into it further.

You can find here the sources (and more) for this article in Eclipse/Maven format.

To go further:

email
Send to Kindle
Categories: Java Tags: ,
  1. April 18th, 2010 at 09:47 | #1

    I have written this library at

    http://code.google.com/p/sbva/

    to allow easy integration of jsr-303 with struts 1. If you try it please let me know what you think.

  2. April 18th, 2010 at 10:17 | #2

    I stumbled upon it when I wrote the article: what’s really missing in your project is the JavaScript generation feature to allow client-side validation like in the Commons Validator Struts integration.

  3. Mohammad
    June 15th, 2011 at 09:10 | #3

    HI,
    i want to ask:
    assume that i have a EmployeeBean, which have name, id, age, dateOfBirth attributes.
    i had used JSR 303 validation on each one of them.
    i have 2 screens(xhtml pages) AddUser Screen, SearchUser Screen(both screens use the same bean).
    i want to disable the JSR 303 validation on SearchUser and Enable it on AddUSer, can i do that? if yes, How?
    thank you

  4. June 15th, 2011 at 10:10 | #4

    @Mohammad
    Since validation is a explicit action i.e. calling validator.validate(), I do not understand your question.

  5. Mohammad
    June 18th, 2011 at 11:02 | #5

    @Nicolas Frankel
    assume that my bean as follow:
    public CarBean{

    @NotNull(message = “The car name cannot be empty”)
    private String carName;

    @NotNull(message = “The car status cannot be empty”)
    private String carStatus;

    @NotNull(message = “The car number cannot be empty”)
    private String carNumber;
    .
    .
    setters and getters here
    .
    .
    now in my addCar.xhtml page the validation is work fine since the 3 filed should field to add a car sucessfully
    but in SearchCar.xhtml page i have the 3 fields, may i want to search based on carName only and left the other fields empty, since all fields have @NOTNULL validation they will result an error,
    my question i want to keep the validation on my AddCar Screen, and disable it on SearchCar, can i do it?

    Regards

  6. June 18th, 2011 at 17:42 | #6

    You’re using JSF, aren’t you? Since JSF uses the Bean validation under the cover, you’ll have to refer to the JSF documentation to know how to disable validation for a page.

  7. Mark
    July 27th, 2011 at 13:17 | #7

    Presumably member validation is done before type validation?

  8. Mark
    July 27th, 2011 at 13:28 | #8

    BTW great article, easily digestible =)

  9. July 29th, 2011 at 15:34 | #9

    Great write up, especially nice to add the legacy perspective so as to understand the divergent needs based on “location”. Thank you.

    There are many strengths to this implementation, however, the only weakness comes in the final step of implementation, setting the validation.

    // Instantiate Class
    Person person = new Person();

    // Set Validation
    Set<Constraintviolation> violations = validator.validate(person);

    Ideally, we would like to see the Validator incorporated in the bean itself, such as in the the constructor. Based on your expertise, what are your thoughts or best practices? The concern is that in a large code base if an inexperienced developer may forget to make the validation association after each “new” of the bean.

  10. July 30th, 2011 at 22:48 | #10

    IMHO, I would suggest you keep the validator and the bean not coupled at all, thus forgetting the Validator incorporated approach. This is because the whole concept of validation depends on the context, not on the bean. For example, an entity could have different validation rules (or no validation at all) in a creation context or in a update context.
    Inexperienced developers (and experienced ones alike) could of course forget, but testing should show this at the earliest time possible.

  11. Rene Felgenträger
    August 25th, 2011 at 11:05 | #11

    Mark,

    u have to explicitly disable the bean validation in the presentation layer (JSF). for this purpose use

    put this tag in a .

    It works in jsf 2.0

  12. Rene Felgenträger
    August 25th, 2011 at 11:05 | #12

    use f:validateBean

  13. jens
    January 14th, 2012 at 22:21 | #13

    hi, super hilfreicher Artikel!! Vielen Dank!! Viele Grüße Jens

  14. February 1st, 2012 at 04:16 | #14

    @Mohammad
    You need to use ValidationGroups.

    public interface CarChecks {
    }

    @NotNull(message = “The car name cannot be empty”, groups=com.CarChecks)
    private String carName;

  1. No trackbacks yet.