Monday, May 23, 2016

Java Bean Validation Gotcha

A well known trick for doing cross field validation using Java Bean Validation (JSR-303) is to simply put an @AssertTrue annotation on a method that actually does the validation, like so:
public class Document {

   @NotNull
   private Status status;   
   private Date signingDate;

   @AssertTrue(message = "A signed document should have a signing date")
   public boolean isASignedDocumentHasASigningDate() {
      return status != SIGNED || signingDate != null;
   }
}
The fact that the assertion method actually returns a boolean also makes unit testing easy. So far so good!

However, there is a little known gotcha related to this: the annotated validation method actually has to follow the naming conventions of a boolean bean property getter, i.e. getBla() or isBla(). In other words the following would not work:

   @AssertTrue(message = "A signed document should have a signing date")
   public boolean aSignedDocumentHasASigningDate() {
      return status != SIGNED || signingDate != null;
   }
That's quite unfortunate, and certainly doesn't follow the principle of least astonishment: we're explicitly annotating the method so there is no reason why the bean validator should not pick it up! Even worse, unless you're thoroughly testing all you bean validation annotations, it's easy to miss the fact that the validation is not actually happening. Something to keep in mind!