JSR-303

Bean Validation
Spring MVC Validator
public interface Validator {

    boolean supports(Class<?> clazz);

    void validate(Object target, Errors errors);
}
Spring MVC Validator
● Spring MVC specific
● Can not be used on client side
● All validation goes to single method
● Hard to make unit tests
Description
"This JSR will define a meta-data model and API
for JavaBeanTM validation based on annotations,
with overrides and extended meta-data through
the use of XML validation descriptors."
Key points
● Configured with annotations
● Not tied to a specific application tier
● Suits both server and client side
Implementations
● Hibernate Validator (reference implementation)
● Apache Bean Validation (incubation)
● GWT Validation
Annotation samples
   @Min         @Future          @Null

       @Past
                      @NotNull
                                   @Digits
@MyCustomMegaConstraint

                                 @Max
                    @Size
     @Pattern
Custom constraint sample
@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = UniqueProductInOrderValidator.class)
public @interface UniqueProductInOrder {

    String message() default "Only unique items";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

}
Bean sample
@UniqueProductInOrder
public class Item {
    private String product;
    @Valid private Order order;

     @NotBlank
     @Length(min = 5, max = 30)
     public String getProduct() {
    return product;
     }
}
Validator sample
public class UniqueProductInOrderValidator implements
          ConstraintValidator<UniqueProductInOrder, Item> {

    @Override
    public boolean isValid(Item v, ConstraintValidatorContext c) {
        Collection<Item> items = value.getOrder().getItems();
         Set<Item> set = new HashSet<Item>(items);
         return set.size() == items.size();
    }
}
Invoke validation sample
@RequestMapping(method = POST)
public String create(@Valid Item item) {
   orderRepository.update(item.getOrder());
   return "redirect:/orders/" + item.getOrder().getId();
}

@ExceptionHandler(BindException.class)
public ModelAndView itemHasErrors(BindException e) {
    return new ModelAndView("addItem", e.getModel());
}
Another sample
@RequestMapping(value = "/orders", method = POST)
public String create(@Valid Order order, BindingResult errors) {

    if (errors.hasErrors()) {
          return null;
    }

    orderRepository.save(order);

    return "redirect:/orders";
}
Groups sample

@GroupSequence({ Item.class, ComplexValidation.class })
@UniqueProductInOrder(groups = ComplexValidation.class)
public class Item {

    @NotBlank
    private String product;

}

interface ComplexValidation {}
Service layer validation
public class SomeService {

    @Inject
    private Validator validator;

    public void doSomething(Item item) {
        Set<ConstraintViolation<Order>> violations =
             validator.validate(item);
    }
}
Unit test sample
@Test
public void noValidationErrorsWhenItemIsValid() {
     Item item = new Item(order, "x", 0);

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

    Set<ConstraintViolation<Item>> violations = validator.validate(item);

    assertTrue(violations.isEmpty());
}
Single property unit test sample
@Test
public void nullProductIsNotAllowed() {
    Item item = new Item(order, null, 0);
     Validator validator =
          Validation.buildDefaultValidatorFactory().getValidator();
    Set<ConstraintViolation<Item>> violations =
          validator.validateProperty(item, "product");
    assertFalse(violations.isEmpty());
}
Hibernate Validator Annotation
              Processor
       Annotation processor based on JSR-269 which plugs
into the build process and raises compilation errors
whenever constraint annotations are incorrectly used.
https://github.com/aleksz/spring-
            reference

Jsr 303

  • 1.
  • 2.
    Spring MVC Validator publicinterface Validator { boolean supports(Class<?> clazz); void validate(Object target, Errors errors); }
  • 3.
    Spring MVC Validator ●Spring MVC specific ● Can not be used on client side ● All validation goes to single method ● Hard to make unit tests
  • 4.
    Description "This JSR willdefine a meta-data model and API for JavaBeanTM validation based on annotations, with overrides and extended meta-data through the use of XML validation descriptors."
  • 5.
    Key points ● Configuredwith annotations ● Not tied to a specific application tier ● Suits both server and client side
  • 6.
    Implementations ● Hibernate Validator(reference implementation) ● Apache Bean Validation (incubation) ● GWT Validation
  • 7.
    Annotation samples @Min @Future @Null @Past @NotNull @Digits @MyCustomMegaConstraint @Max @Size @Pattern
  • 8.
    Custom constraint sample @Target(TYPE) @Retention(RUNTIME) @Constraint(validatedBy= UniqueProductInOrderValidator.class) public @interface UniqueProductInOrder { String message() default "Only unique items"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
  • 9.
    Bean sample @UniqueProductInOrder public classItem { private String product; @Valid private Order order; @NotBlank @Length(min = 5, max = 30) public String getProduct() { return product; } }
  • 10.
    Validator sample public classUniqueProductInOrderValidator implements ConstraintValidator<UniqueProductInOrder, Item> { @Override public boolean isValid(Item v, ConstraintValidatorContext c) { Collection<Item> items = value.getOrder().getItems(); Set<Item> set = new HashSet<Item>(items); return set.size() == items.size(); } }
  • 11.
    Invoke validation sample @RequestMapping(method= POST) public String create(@Valid Item item) { orderRepository.update(item.getOrder()); return "redirect:/orders/" + item.getOrder().getId(); } @ExceptionHandler(BindException.class) public ModelAndView itemHasErrors(BindException e) { return new ModelAndView("addItem", e.getModel()); }
  • 12.
    Another sample @RequestMapping(value ="/orders", method = POST) public String create(@Valid Order order, BindingResult errors) { if (errors.hasErrors()) { return null; } orderRepository.save(order); return "redirect:/orders"; }
  • 13.
    Groups sample @GroupSequence({ Item.class,ComplexValidation.class }) @UniqueProductInOrder(groups = ComplexValidation.class) public class Item { @NotBlank private String product; } interface ComplexValidation {}
  • 14.
    Service layer validation publicclass SomeService { @Inject private Validator validator; public void doSomething(Item item) { Set<ConstraintViolation<Order>> violations = validator.validate(item); } }
  • 15.
    Unit test sample @Test publicvoid noValidationErrorsWhenItemIsValid() { Item item = new Item(order, "x", 0); Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Set<ConstraintViolation<Item>> violations = validator.validate(item); assertTrue(violations.isEmpty()); }
  • 16.
    Single property unittest sample @Test public void nullProductIsNotAllowed() { Item item = new Item(order, null, 0); Validator validator = Validation.buildDefaultValidatorFactory().getValidator(); Set<ConstraintViolation<Item>> violations = validator.validateProperty(item, "product"); assertFalse(violations.isEmpty()); }
  • 17.
    Hibernate Validator Annotation Processor Annotation processor based on JSR-269 which plugs into the build process and raises compilation errors whenever constraint annotations are incorrectly used.
  • 18.