I recently had a chance to actually use the new Bean Validation spec. in one of my projects. As the developer of the Bean Validation Framework for Spring (part of the springmodules project) it of course feels a bit weird to ditch all the work I’ve done, but at the same time, it also feels good to use a standard spec that very soon will be finalized. As a member of the JSR-303 expert group (although quite a quiet member) I can assure you that the guys (special kudo’s to Emmanuel Bernard) worked really hard to come up with a specification that will fit in many of the different programming models and technologies we all use (e.g. JPA, JSF, Swing, etc..). In this writing, I’d like to show you a how you can integrate Bean Validation in your Spring based application, especially  if you’re using Spring MVC. Please note, that Spring 3.0 promises to bring such support out of the box, but the last time I checked, it wasn’t implemented yet, and besides, if you’re using Spring 2.x you may find this useful as well.

JSR-303

JSR-303 is a specification for Bean Validation. The work on it started around one and a half years ago as an attempt to come up with a standard declarative validation framework. With Java 5 release and the introduction of annotations, more and more framework developers realized the potential of declarative validation. WebWork had it, Hiberante came up with the Hibernate Validator framework, and I developed such support for spring. We all had the same idea’s, we all shared the same points of views and it was just a matter of time until this would be standardized.

The goal of this specification is not to provide one solution to fit all your validation needs – not at all. There are many types of constraints in an application that span different layers. Data constraints on the database level, business rules on the service level, and even UI constraints purely on the UI level. JSR-303 target what I like to refer to as the model constraints. The idea is very simple – some constraints on your model are tightly coupled to it and therefore belongs next to it. The infrastructure defined by JSR-303 enables you to do that – you can describe the constraints using constraint annotations on your model and validate your model using constraint validators.

As in most cases, an example works best, so let’s look at one. Consider having a class representing an email message with the following constraints:

  • The from property should not be empty and represent an email
  • The to property should not be empty and represent an email
  • The subject is not empty
  • The body is not empty

Here is how you can model it as a java bean and define these constraints:

public class Email {

    @NotEmpty @Pattern(".+@.+\\.[a-z]+")
    private String from;

    @NotEmpty @Pattern(".+@.+\\.[a-z]+")
    private String to;

    @NotEmpty
    private String subject;

    @NotEmpty
    private String body;

    // setters and getters
    ...
}

NOTE: it is possible to put the annotations on the fields or on the setter methods of the bean properties. Personally I like putting them on the fields as it’s easier to pick up when reading the code.

Here’s the code that actually validates an email object based on these constraints:

Email email = new Email();
email.setFrom("john@domain.com");
email.setTo("someone");
email.setSubject("");
email.setBody(null);

ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.getValidator();

Set<ConstraintViolation<Email>> violations = validator.validate(email);
for (ConstraintViolation<Email> violation : violations) {
    String propertyPath = constraintViolation.getPropertyPath().toString();
    String message = constraintViolation.getMessage();
    System.out.println("invalid value for: '" + propertyPath + "': " + message);
}

In lines 1-5 we construct the email object and initialize it with invalid data (the to property does not represent a valid email, the subject is empty and the body is null). In lines 7-8 the Validator is created using the default ValidatorFactory. And finally, in lines 10-15, we perform the validation and iterate over the constraint violations that the validator generated.

Spring Validation

Spring has its own mechanism to do validation. It is not declarative but very flexible and extensible. It is mostly used in SpringMVC to preform validation of command object that are bound to request parameters before they are sent to the controllers. In spring the main validation construct is the Validator interface:

public class Validator {

    boolean supports(Class type);

    void validate(Object target, Errors errors);

}

The supports method indicates whether the validator can validate a specific class. If so, the validate method can be called to validate an instance of that class. The implementation of this method can then register any validation errors that it encounters with the passed in Errors instance.

Although spring doesn’t come with any default implementation of this interface, it does comes with the ValidationUtils class which provides a few helper methods to perform some common validations. Here is the same example as above, but this time the validation is done using a Spring Validator:

public class EmailValidator implements Validator {

    private final static Pattern EMAIL_PATTERN = Pattern.compile(".+@.+\\.[a-z]+");

    public boolean supports(Class type) {
        return Email.class.equals(type);
    }

    public void validate(Object target, Errors errors) {
        Email email = (Email) target;

        String from = email.getFrom();
        if (!StringUtils.hasText(from)) {
            errors.rejectValue("from", "required");
        } else if (!isEmail(from)) {
            errors.rejectValue("from", "invalid.email");
        }

        String to = email.getTo();
        if (!StringUtils.hasText(to)) {
            errors.rejectValue("from", "required");
        } else if (!isEmail(to)) {
            errors.rejectValue("from", "invalid.email");
        }

        ValidationUtils.rejectIfEmpty(errors, "subject", "required");
        ValidationUtils.rejectIfEmpty(errors, "body", "required");
    }

    private boolean isEmail(String value) {
        return EMAIL_PATTERN.matcher(value).matches();
    }
}

Now that we’ve defined the validator, we can perform the validation as follows:

Email email = new Email();
email.setFrom("john@domain.com");
email.setTo("someone");
email.setSubject("");
email.setBody(null);

BindException errors = new BindException("email", email);
EmailValidator validator = new EmailValidator();
validator.validate(email, errors);

for (FieldError error : (List<FieldError>) errors.getFieldErrors()) {
    System.out.println("invalid value for: '" + error.getField() + "': " + error.getDefaultMessage());
}

Enjoy both worlds

As you can see, declarative validation is much more elegant, expressive, and in general simpler to use when compared to the classic Spring valiator way. On the other hand, the spring validation mechanism is well integrated in Spring MVC and if you’re using it for your web development, you probably want to take advantage of that. So what we’re really looking for is a way to enjoy both worlds. Luckily, due to the extensible nature of the Spring validation mechanism, we can easily get there. The idea is to simply create a spring validator implementation which delegates the validation tasks to the JSR-303 validator. So let’s do that:

First you’ll need to get a hold of the latest version of the reference implementation for JSR-303. You can either download the following jars manually:

http://repository.jboss.com/maven2/javax/validation/validation-api/1.0.CR3/validation-api-1.0.CR3.jar

http://repository.jboss.com/maven2/org/hibernate/hibernate-validator/4.0.0.Beta2/hibernate-validator-4.0.0.Beta2.jar

Or, if you’re using maven (like me) you can just add the following to your pom:

<repositories>
    <repository>
        <id>jboss</id>
        <url>http://repository.jboss.com/maven2</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>4.0.0.Beta2</version>
    </dependency>
</dependencies>

Assuming you have your project setup already and spring configured, let’s look at the BeanValidator implementation:

public class BeanValidator implements org.springframework.validation.Validator, InitializingBean {

    private Validator validator;

    public void afterPropertiesSet() throws Exception {
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.usingContext().getValidator();
    }

    public boolean supports(Class clazz) {
        return true;
    }

    public void validate(Object target, Errors errors) {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target);
        for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
            String propertyPath = constraintViolation.getPropertyPath().toString();
            String message = constraintViolation.getMessage();
            errors.rejectValue(propertyPath, "", message);
        }
    }
}

Since the validation framework can potentially validate any object, the supports method return true to all types. Also notice that the bean validator is actually created at load time. This is fine as according to the spec. a Validator instance must be thread safe – this means that we can register this BeanValidator as a singleton in the application context and reuse it in all our controllers. All the validate method does is translate the constraint violations to error messages which are registered with the passed in errors instance.

Now that we have the BeanValidator ready, all that is required in order to use it is to register it in the application context. If you’re using spring’s component-scaning mechanism, you can simply annotate it with the @Component annotation, otherwise you can just add the following line to your application context configuration:

<bean id="beanValidator" class="package.name.BeanValidator"/>

Done! You can now inject this validator to all your SpringMVC controllers and benefit from the JSR-303 declarative validation.

Writing you own custom constraints

JSR-303 defines a set of constraints that should be supported out of the box by all providers. But this is a relatively limited set and when developing real world application you’ll probably find the need to extend it and provide your own custom constraints. There are two ways of doing this – write it from scratch or combine a constraints from other already existing constraints.

Writing from scratch

To write a new constraint from scratch you first need to know how JSR-303 constraints work.

A constraint is basically a pair of an annotation and its associated validator class. When a bean is validated, it is being scanned for all the constraint annotations. Once such annotation is found its associated validator is created and initialized with the annotation (the annotation in a way serves as the configuration for its validator). How does the framework know which validator to instantiate? well… the annotation indicates it, and it’s best explained by an example.

In the first example above, we showed how one can validate an email using the @Pattern annotation. It would be much more expressive (and semantically right) if we would have an @Email annotation instead which would also relieve us from remembering the email regular expression each time we need to apply this constraint. To make it work we’ll first define the @Email annotation:

@Documented
@Constraint(validatedBy = EmailValidator.class)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface Email {

    public abstract String message() default "{package.name.Email.message}";

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

    public abstract Class<? extends ConstraintPayload>[] payload() default {};

}

All the defined attributes in this annotation are specified in the spec. and mandatory for all constraint annotations. I will not discuss the payload and groups attributes but the message attribute defines the error message that should be used in case the constraint is violated. Beside these mandatory attributes, each constraint annotation can define additional attributes as needed. In our example, there no such need, but a @Range annotation for example, which can be used to define the boundaries of an integer value, will probably define a min and a max attributes.

NOTE: The specification define quite a powerful message interpolation mechanism for the error messages. The message can contain placeholders (surrounded by curly brackets) which can be replaced by the attributes defined in the annotation itself. Furthermore, the placeholders can also refer to keys defined in a resource bundle. In the later case the placeholders will be replaced by their associated values in the bundle. For example, as we did in the @Email annotation, it is considered a best practice to assign a default message value. This value actually consists of one parameter placeholder which refers to a key in a resource bundle (“package.name.Email.message“). When the error message is resolved, the value of this key is looked up in the resource bundle and when found replaces the placeholder. By default, the validator will look for a resource bundle named ValidationMessages.properties in the classpath.

Notice that the @Email annotation itself is annotated with a @Constraint annotation. This annotation indicates that @Email is a constraint. The validatedBy attributes indicates the validator class which should be used to validate the constraint. This is how the bean validator knows which constraint validator class to instantiate. Let’s look at the EmailValidator class:

public class EmailValidator implements ConstraintValidator<Email, String> {

    private final static Pattern EMAIL_PATTERN = Pattern.compile(".+@.+\\.[a-z]+");

    public void initialize(Email constraintAnnotation) {
        // nothing to initialize
    }

    public boolean isValid(String value, ConstraintValidatorContext context) {
        return EMAIL_PATTERN.matcher(value).matches();
    }
}

The first thing to note about this class is that it implements the ConstraintValidator interface. This interface accepts two generic types – the first indicates the annotation it is associated with (@Email in our case) and the second indicates the type of objects it can validate (String in our case).

The initialize method (line 5) is called after the constraint validator is instantiated. The constraint annotation is passed in as the configuration. Continuing the @Range example from above, a RangeValidator will probably extract the min and max values from the annotation which will later be used to perform the actual range validation.

The isValid method (line 9) does the actual validation. This is where you need to put the validation logic, which in our case, is just matching the string to an email regular expression.

The only thing that is left to do, is to create a ValidationMessage.properties file and put it in the classpath. This is the user defined resource bundle that the bean validator work with by default. Now, add the default error message code to it to provide a default user friendly message:

package.name.Email.message=Invalid email

Thats it, you’re done. You can change the original code of our email example to use this new annotation (instead of the @Pattern annotation) and see it in action.

Composing annotations

Sometimes there is no real need to create constraint entirely from scratch. It is often the case where a constraint is either a specific variation of another constraint, or a combination of other finer grained constraints. The specification acknowledges that and makes it even easier to define such constraints.

Take the @Email constraint for example. Instead of creating a validator for it, we can also view this constraint as a narrowed version (or a specific case) of the @Pattern constraint. So we can actually compose it instead of creating from scratch.

In order to compose an annotation, all that is needed is to annotate the new constraint annotation with the constraint annotations that compose it. hmmm… confuse? well, an example will clear it up. Here is the @Email annotation again, yet this time it is composed of the standard @Pattern annotation:

@Documented
@Constraint(validatedBy = {})
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Pattern(regexp = ".+@.+\\.[a-z]+")
@ReportAsSingleViolation
public @interface Email {

    public abstract String message() default "{package.name.Email.message}";

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

    public abstract Class<? extends ConstraintPayload>[] payload() default {};

}

As you can see, no validator is associated with this annotation. Instead, it is annotated with the @Pattern annotation which holds the email regular expression. By default, when the validation is performed, all the composing constraints are evaluated (in our case, the @Patterm constraint) and register any encountered violations. It is sometimes (if not often) the case where you’d like only one error message to be reported – in our case, an “invalid email” message (not a “pattern mismatch” message). This is where the @ReportAsSingleViolation annotation becomes useful. This annotation indicates that on any constraint violation of any of the composing constraints, only one violation will be reported and it is of the composed constraint – all the other reported violations of the composing annotations will then be ignored.

Loading constraint validators from spring

As you’ve seen, the default implementation of the Validator instantiates the ConstraintValidators via reflection. Although good enough for most cases, sometimes the validation logic requires interaction with external services (for example, finding out whether a username is unique in the system). If you have this requirement and you’re using spring, you probably want these services to be injected into the validator, and in fact, let spring instantiate the validator all together. To achieve that you’ll need to modify the BeanValidator implementation a bit:

public class BeanValidator implements org.springframework.validation.Validator,
        InitializingBean, ApplicationContextAware, ConstraintValidatorFactory {

    private Validator validator;

    private ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    public void afterPropertiesSet() throws Exception {
        ValidatorFactory validatorFactory = Validation.byDefaultProvider().configure()
                .constraintValidatorFactory(this).buildValidatorFactory();
        validator = validatorFactory.usingContext().getValidator();
    }

    public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {

        Map beansByNames = applicationContext.getBeansOfType(key);
        if (beansByNames.isEmpty()) {
            try {
                return key.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException("Could not instantiate constraint validator class '" + key.getName() + "'", e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Could not instantiate constraint validator class '" + key.getName() + "'", e);
            }
        }
        if (beansByNames.size() > 1) {
            throw new RuntimeException("Only one bean of type '" + key.getName() + "' is allowed in the application context");
        }
        return (T) beansByNames.values().iterator().next();
    }

    public boolean supports(Class clazz) {
        return true;
    }

    public void validate(Object target, Errors errors) {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target);
        for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
            String propertyPath = constraintViolation.getPropertyPath().toString();
            String message = constraintViolation.getMessage();
            errors.rejectValue(propertyPath, "", message);
        }
    }

As you can see, out BeanValidator now implements two additional interfaces. The first is Spring’s ApplicationContextAware interface. This will cause the application context to be injected into the validator. The second interface is the ConstraintValidationFactory. It is a JSR-303 interface which abstract the way the constraint validators are constructed. In our case, we first try to find a bean in the application context that matches the type of the constraint (lines 20-29). If none is found, we just instantiate the constraint class using reflection. Otherwise, we make sure that there’s only one bean definition of the constraint class and if so, it is returned (lines 30-33). The last change we needed to make in order for it to work is to configure the validator factory to use the new constraint validator factory. You can see how this is done at lines 13-14. Now, if your constraint validator requires other services, just add it to the application context, configure its dependencies and you’re done.

Conclusion

Well, that’s it for this entry. I tried to introduce you to the new JSR-303 bean validation specification and show you how you can already work and integrate with your spring applications. You have to remember though, that this spec is still undergoing some last changes and is not final yet (though personally, I don’t expect to see any major changes in the final version).

For me, although it’s not final yet and although the reference implementation is still in beta, I already feel comfortable using it in a real world project. Yes, there might be some bugs (they are fixed pretty quickly once reported), and I might need to change a few little things when the final release is out, but at the same time, I benefit from cleaner code that confirms to the standards and it always makes me happy when my projects are up to date with the latest and greatest technologies out there.