2010-07-21

Custom validation with Bean Validation (JSR-303)

In my previous post on Bean Validation I explained how to use built-in constrains. When the standard constraints aren’t enough, you can develop your own.


Custom constraint


Let’s create a custom constraint and have it checked that the first character is an uppercase one.

package me.m1key.jsf.constraints;

import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import javax.validation.Constraint;
import javax.validation.Payload;

@Documented
@Constraint(validatedBy = FirstUpperValidator.class)
@Target( { METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface FirstUpper {
 String message() default "{me.m1key.jsf.constraints.FirstUpper.message}";

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

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

  • message - the error message. You can omit curly braces and just hard code it
  • groups - this is for grouping validations (if one group fails - other groups are not checked; here we use the default group)
  • payload - additional type-safe information might be carried here

Now, we need the validator.


Custom validator


package me.m1key.jsf.constraints;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class FirstUpperValidator implements
     ConstraintValidator<FirstUpper, String> {

 @Override
 public void initialize(FirstUpper firstUpper) {
     // See JSR 303 Section 2.4.1 for sample implementation.
 }

 @Override
 public boolean isValid(String value, ConstraintValidatorContext context) {
     if (value == null || value.length() == 0) {
         return true;
     }
     return value.substring(0, 1)
             .equals(value.substring(0, 1).toUpperCase());
 }
}

Nothing special here. Finally, the usage...


The usage


It’s identical as any other constraint.
@NotNull
  @Size(min = 3)
  @FirstUpper
  public String getName() {
      return name;
  }


Summary


I showed you how to write custom constraints and gave a hint about existence and purpose of groups and payloads.

Download source code for this article

Read on

2 comments: