Just say no to Scarlett Johansson, Brad Pitt and the rest (but say yes to Bean Validation)!

Every single application with user interaction needs some sort of validation. Java EE 6 now has its very own standard Bean Validation API (JSR 303) with a number of easy-to-use built-in constraints (@NotNull, @Size, …). GlassFish v3 ships with the Hibernate Validator reference implementation which offers some additional annotations such as @Email. I’ve decided for the sake of this blog entry that it was not good enough for me as it considers null, empty and foo@barcom as all valid (and does the check as part of the ConstraintValidator, not in the definition of the @Email annotation).

So here’s my new implementation of a constraint to check for valid email addresses with the additional feature of rejecting dummy data, such as angelina.jolie@foo.bar (too bad it it was the real one trying to post a comment to your blog or mine!). In my implementation the annotation constraint is called @EmailAddress and defined as follows :

@Size(min=5, message="{foo.bar.min_size}")
@Pattern(regexp="[a-z0-9!#$%&'\*+/=?\^_`{|}~-]+(?:\\\\.[a-z0-9!#$%&'\*+/=?\^_`{|}~-]+)\*" +
                 "@" +
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
public @interface EmailAddress {
     String message() default "{foo.bar.invalid_email}";
     Class[] groups() default {};
     Class[] payload() default {};

Things to note:

• A constrained value can fail one or more validation tests in no particular order. Each failure will be reported and available upon validation. In particular you cannot assume that the data passed to the constraint validator will not be null (and the use of @NotNull could arguably be removed since nullability is tested in the validation code below).

• I’m using the @Pattern annotation here rather than manipulating the regex in the explicit validation code (the regex itself comes from a slightly simplified version of the one defined by RFC 2822).

• error messages use externalized strings located in a resources bundle ValidationMessages.properties file.

Here’s the rather straightforward validation code (see @Constraint above) :

public class EmailValidator implements ConstraintValidator<EmailAddress, String> {
     ArrayList<String> blackListedDomains;
     ArrayList<String> blackListedNames;

     public void initialize(EmailAddress constraintAnnotation) {
         // a better implementation would probably retrieve data
         // from a file, a database or a web service.
         blackListedDomains = new ArrayList<String>();

         blackListedNames = new ArrayList<String>();

     public boolean isValid(String value, ConstraintValidatorContext context) {
         int at = value.indexOf('@');
         if (value == null || "".equals(value) || at<0 ) return false;

         String username = value.substring(0, at).toLowerCase();
         String domainname = value.substring(at+1).toLowerCase();

         if ( blackListedDomains.contains(domainname) ) return false;
         if ( blackListedNames.contains(username)) return false;

         return true;

The main thing to notice in the code above is the use of generics in ConstraintValidator interface which in turn defines the argument types in the initialize() and isValid() methods.

This newly defined @EmailAddress constraint can now be applied to class attributes or getters. In the case of JPA entities or JSF attributes there is no extra step, all the glue is provided to validate data upon calling the JPA life-cycle methods and applying the JSF request life-cycle, with error messages surfaced to the user via those two APIs. In other cases, Bean Validation offers API to explicitly validate the data illustrated in this sample unit test :

public class TestEmailConstraint {
    Validator validator;
    Customer myCustomer;

    public void setUp() {
       ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
       validator = factory.getValidator();
       myCustomer = new Customer();

    public void testEmailBV() {
       Set<ConstraintViolation<Customer>> violations = validator.validate(myCustomer);
       for (ConstraintViolation<Customer> violation : violations) {
          System.out.print(violation.getInvalidValue() + " => ");
       assertTrue(violations.size() > 0);

Author: alexismp

Google Developer Relations in Paris.

4 thoughts on “Just say no to Scarlett Johansson, Brad Pitt and the rest (but say yes to Bean Validation)!”

  1. I’m not a big fan of combining random libraries and being lazy as well, I have just one Maven dependency :
    with a deployment to GlassFish v3. Try that.

  2. Ah I forgot about that dependency :) Thanks, will try it out. Though I’m testing on Tomcat – mainly due to the rest of the team using Tomcat – so not sure if it’ll work. Will eventually be deploying to JBoss, which I assume will work.

Comments are closed.