Search code examples
javahibernateannotationsbean-validationhibernate-validator

How to implement multiple JSR-303 validation messages for the same @Constraint?


I'm using JSR-303 validation (hibernate-validator) for an entity with a few different rules to be applied. Would rather not stack up multiple @Constraint annotations for these and instead use a single one, e.g. @MyEntityConstraint.

Problem is there really needs to be a different message for each type of validation failure but the message seems inextricably associated with the annotation:

public @interface MyEntityConstraint {
    String message() default "A single, unchangeable message per constraint???";
    // ...
}

Is there any way round this or am I doomed to have:

@MyEntityConstraint1
@MyEntityConstraint2
// ...
@MyEntityConstraintn
@Entity
public class MyEntity {
    // ...
}

Solution

  • As suggested by Hardy, this can be done simply enough using ConstraintValidatorContext - as below:

    @Override
    public boolean isValid(MyEntity myEntity, ConstraintValidatorContext context) {
        // Disable default ConstraintViolation so a customised message can be set instead.
        context.disableDefaultConstraintViolation();
    
        return checkConstraint1(myEntity, context)
               && checkConstraint2(myEntity, context)
               //...
               && checkConstraintn(myEntity, context);
    }
    
    // Note: A private method for each constraint decreases the cyclomatic complexity.
    private boolean checkConstraint1(MyEntity myEntity, ConstraintValidatorContext context) {
        // Default validity is true until proven otherwise.
        boolean valid = true;
    
        if (/*<<Insert constraint #1 conditions (about myEntity) here>>*/) {
            valid = false;
            context.buildConstraintViolationWithTemplate(
               "<<Insert constraint #1 failure message here>>").addConstraintViolation();
        }
    
        return valid;
    }