Search code examples
javavalidationbean-validation

Delegating (generic) constraint definition annotation


In JSR-303 (Bean Validation) you need to define a special annotation for each constraint validator you write. This makes perfect sense if you are creating reusable constraint validators (like the standard @Max, @NotNull, etc).

However in real life every validated bean requires its own validator to do more complex business validations. With vanilla JSR-303 implementations you have to create a separate annotation for every validator. This forces developer to write one-time-only annotations and makes the overall concept of bean validation look stupid. The necessity for one-time-only annotations can be avoided if JSR-303 offers some sort of delegating constraint annotation: @ValidateBy(validator=my.custom.Validator).

Now to my question:

  • Why doesn't JSR-303 include such use-case?
  • Is there any official discussion related to this (I was not able to find anything)?
  • Do any JSR-303 library offer such functionality (not that it would be hard to implement that)?

UPDATE 1 - Specific use-case (which led to this question)

We have a moderate enterprise application with pretty rich business model (40 manageable entities, 20 embeddable entities, 25 read-only entities). This means that we have a lots of HTML forms. Each form is backed by a designated form bean (70 form beans) with JSR-303 annotations. Some forms require custom non-trivial validation (e.g. if delivery type is email then a contact email must be set, ...). With JSR-303 we have 33 form-bean specific validators with 33 (unnecessary one-time-only) annotations.

With the number of Java classes (entities, controllers, DAOs, DTOs, mappers, validators, etc... right now this makes 800 .java files) I don't like having any boilerplate code around.


Solution

  • Sometimes you need to ask the question to realize how to solve "the problem" yourself. Based on Gunnar's answer and comments:

    You can create @MyDomainModelValid constriant definition for the custom domain model with all the necessary validators:

    @Target({TYPE})
    @Retention(RUNTIME)
    @Constraint(validatedBy={
            MyFirstEntityValidator.class, MySecondEntityValidator.class,
            MyThirdEntityValidator.class, EtCetera.class})
    public @interface MyDomainModelValid {
        String message() default "entity.notValid";
        Class<?>[] groups() default { };
        Class<? extends Payload>[] payload() default {};
    }
    

    JSR-303 implementation will make sure that a correct validator is called for a specific entity. So there is no need for previously proposed @ValidatedBy annotation.