Red Hat
Dec 3, 2009
by Emmanuel Bernard

Now that Bean Validation is officially part of Java EE 6 and that Java EE6 is officially voted YES, let's see how Bean Validation integrates with the rest of the eco system.

What is Bean Validation

It's goal is to let application developers declare their data constraints once by annotating their model and make sure these constraints are validated by the different layers of the application in a consistent manner. Without Bean Validation, people have to write their validation rules in their favorite presentation framework, then in their business layer, then in their persistent layer, to some degree in the database schema and keep all of them synchronized.

Here is how this centralized constraint declaration looks like:

class User {
  @NotEmpty @Size(max=100)
  String getLogin() { ... }

  @NotEmpty @Size(max=100)
  String getFirstname() { ... }
  
  @Email @Size(max=250)
  String getEmail() { ... }
  ...
}

There are many more features like constraint composition, grouping but let's focus on how Bean Validation integrates with the EE 6 stack.

So what do I have to do to make it work in Java EE 6

The short answer is nothing. Not even an XML configuration trick.

Simply add your constraints on your domain model and the platform does the rest for you.

JSF and how to expose constraint violations to the user

In JSF, you bind form inputs to properties of your domain model. JSF 2 and Bean Validation smartly figure out which property you are binding to and execute the constraints associated to it.

<h:form id="register">
    <div style="color: red">
        <h:messages id="messages" globalOnly="true"/>
    </div>

    <div>
        Login:
        <h:inputText id="login" value="#{identifier.user.login}"/>
        <h:message style="color: red" for="login"/>
        <br/>
        Password:
        <h:inputSecret id="password" value="#{identifier.user.password}"/>
        <h:message style="color: red" for="password"/>
        <br/>
        Firstname:
        <h:inputText id="firstname" value="#{identifier.user.firstname}"/>
        <h:message style="color: red" for="firstname"/>
        <br/>
        Email:
        <h:inputText id="email" value="#{identifier.user.email}"/>
        <h:message style="color: red" for="email"/>
        <br/>

        <h:commandButton id="Login" value="Login" action="#{identifier.register}"/>
        <br/>
        <h:button id="cancel" value="Cancel" outcome="/home.xhtml"/>
    </div>
</h:form>

If the email, for example is malformed and the first name is left empty, Bean Validation will return the constraint violations to JSF 2 that will expose them to the user in a localized error message. By default, it just works and you don't even have to think about it.

For more advanced use cases, like disabling constraint validation for one or several fields or using a specific group or set of groups instead of the default one, you can use the <f:validateBean/> tag (check line 8 and 20 in the following example).

<h:form id="register">
    <div style="color: red">
        <h:messages id="messages" globalOnly="true"/>
    </div>

    <div>
        <!-- ***** use a specific group ***** -->
        <f:validateBean validationGroups="${identifier.validationGroups}">
            Login:
            <h:inputText id="login" value="#{identifier.user.login}"/>
            <h:message style="color: red" for="login"/>
            <br/>
            Password:
            <h:inputSecret id="password" value="#{identifier.user.password}"/>
            <h:message style="color: red" for="password"/>
            <br/>
            Firstname:
            <!-- ***** disable validation for firstname ***** -->
            <h:inputText id="firstname" value="#{identifier.user.firstname}">
                <f:validateBean disabled="true"/>
            </h:inputText>
            <h:message style="color: red" for="firstname"/>
            <br/>
            Email:
            <h:inputText id="email" value="#{identifier.user.email}"/>
            <h:message style="color: red" for="email"/>
            <br/>

            <h:commandButton id="Login" value="Login" action="#{identifier.register}"/>
            <br/>
            <h:button id="cancel" value="Cancel" outcome="/home.xhtml"/>
        </f:validateBean>
    </div>
</h:form>

In the future, we want to work with RichFaces so that the constraints declared on the object model are validated in the JSF components on the client side. This is something we had prototyped already and that Pete, Dan and I proposed to the JSF 2 expert group initially but we had to scale down our ambitions :) Expect some innovations from us in this area.

But not all your data comes from the presentation layer.

JPA 2: last line of defense

Again, by default, your JPA 2 provider runs Bean Validation on the entities you are about to persist or update. You are then guaranteed to not put invalid data in your database and thus increasing the quality of your data overall. Oh, and these are the same constraints you would have validated in JSF 2.0.

You can disable validation in JPA 2 using the validation-mode element in persistence.xml or the javax.persistence.validation.mode property and set them to none. More interestingly, you can chose which group will be validated upon entity persist, update and even delete operations. By default, the Default group is validated when you persist or update entities. Use any one of these properties to adjust that.

<property name="javax.persistence.validation.group.pre-persist" 
        value"javax.validation.groups.Default, com.acme.model.Structural"/>
<property name="javax.persistence.validation.group.pre-update" 
        value"javax.validation.groups.Default, com.acme.model.Structural"/>

<property name="javax.persistence.validation.group.pre-delete" 
        value"com.acme.model.SafeDestruct"/>

Hibernate Core and Hibernate Validator go a bit beyond that and propagate the constraints to the database schema (provided that you let Hibernate Core generate or update the schema for you). Simply set the hibernate.hbm2ddl.auto property to create, update or create-drop.

How about my service layer

You can inject a Validator or ValidatorFactory instance in any injectable POJO in Java EE 6.

class SalesService {
  @Inject Validator validator;
  @Inject @Current User user;

  public boolean canBuyInOneClick() {
    return validator.validate(user, BuyInOneClick.class).size() == 0;
  }

Where can I try it?

All of this is now available in JBoss AS 6 M1 that have just been released. Enjoy!