Over a million developers have joined DZone.
Gold Partner

Be Standard, be Free: Use JSR-303 for Validation

· Java Zone
No matter what type of application we develop, coding validations is our everyday task. For years we have used a big variety of techniques and frameworks for validation with success. However, flor some time we have a standard in Java for validation, the Bean Validation specification (JSR-303). The question is: is it worth writing (or rewriting) our validations using the Bean Validation standard? Is there some practical advantage in use JSR-303?
First, let's write a validator (constraint in Bean Validation nomenclature) and then let's use it in our code, to see what we are talking about.

Creating a JSR-303 constraint

A JSR-303 constraint is just a plain Java annotation. For example, if we want to validate ISBNs, we have to create an @ISBN annotation like the next one:

package org.openxava.books.constraints;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
import javax.validation.*;
import org.openxava.books.constraints.impl.*;

@Constraint(validatedBy = ISBNValidator.class) // ISBNValidator contains the validation logic
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
public @interface ISBN {

String message() default "{org.openxava.books.constraints.ISBN.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };

}

The key part here is the @Constraint annotation. It marks this annotation as a constraint and indicates the validator class, ISBNValidator, that is the class with the validation logic:

package org.openxava.books.constraints.impl;

import javax.validation.*;
import org.openxava.books.constraints.*;

public class ISBNValidator implements ConstraintValidator<ISBN, String> {

private static org.apache.commons.validator.ISBNValidator validator =
new org.apache.commons.validator.ISBNValidator(); // Validator from commons validator

public void initialize(ISBN isbn) {
}

public boolean isValid(String value, ConstraintValidatorContext ctx) { // The validation logic
if (value == null || value.trim().equals("")) return true;
return validator.isValid(value); // We simply delegate in commons validator
}

}

The validator must implement ConstraintValidator, so it needs to have the initialize() and isValid() methods, the latter contains the validation logic. In this case we simply delegate in a validator from Apache Commons Validator project.
As we can see create a validator is pretty simple. Now, how can we use this validation in our application?

Using the validator

The JSR-303 specification talks about how to define validators, but not about how they are used and behave in our application, this depends on the framework we are using. JPA2 and JSF2 have Bean Validation integration, moreover many modern frameworks have support for JSR-303 as well. In this case we are going to develop a mini-application using the OpenXava framework that use the above @ISBN application. Don't panic, developing an OpenXava application is short (and sweet), given we only need to write the domain classes.
After creating a new OpenXava project (executing an ant target) we add the Author and Book classes to it.

Author.groovy:

package org.openxava.books.model

import javax.persistence.*
import org.openxava.model.*
import org.openxava.annotations.*

@Entity
class Author extends Identifiable {

@Required
String name

}

Book.groovy:

package org.openxava.books.model

import org.openxava.model.*;
import org.openxava.annotations.*;
import org.openxava.books.constraints.*;
import javax.persistence.*;

@Entity
class Book extends Identifiable {

@Required @Column(length=60)
String title

@ManyToOne(fetch=FetchType.LAZY)
@DescriptionsList
Author author

@Column(length=10)
@ISBN
String isbn

}

Although we could write the classes with Java, we have chosen Groovy. Yes, Groovy Web Development without Grails is possible. However, the important point here is the @ISBN annotation in isbn property. We do not need more work to see the validation working. If we go to http://localhost:8080/Books/modules/Book, and we try to add a Book with an incorrect ISBN, we'll get something like this:

As we can see using the @ISBN validation in our application is a completely declarative task, so dead easy.

Why should I use Bean Validation?

Though JSR-303 is easy to use and versatile enough to meet our validation needs, really is not something spectacular, and possibly not much better than our current validation framework, so, why should we use it? Because it is supported by JPA2, JSF2, Spring Roo, Wicket, Tapestry, etc. in addition to be included as part of Java EE 6. Therefore, it gives us more freedom, because our code is less dependent from the application framework we are using, thus it's easier to migrate our code (at least the model part) from Wicket to Tapestry, or from Spring Roo to OpenXava.

 

Use the Bean Validation standard. Be free!

Resources

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}