We are using the JSR 303 Bean validation API (Hibernate validator as the implementation) on a project and recently faced a problem.
Whenever we were using our own custom validators in combination with standard validators like NotNull and NotEmpty, the standard validators seemed to be ignored.
The result was that we were getting NullPointerExceptions in our custom validators and sometimes we were getting duplicate error messages for the same invalid field.
I haven’t poured over all of the JSR 303 documentation in detail so maybe I’ve missed a recommended best practice but the following code in the default NotBlankValidator gave me a hint.
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { if ( s == null ) { return true; } ...
Why would you ever return true (i.e. valid) for an input that is null? That doesn’t make sense until you realise that validation is a *combination* of all constraints.
This means that your validator should only return false for your specific test. If it fails for a chained validation, for example if input is null, it should return true and rely on the NotNull validation to report that error.
You still have to guard for null and empty inputs but return true if they occur rather then returning false.
Hide any required basic validations inside your custom constraint annotation. For example NotBlank does that:
... @NotNull public @interface NotBlank { ...