This topic has not yet been written. The content below is from the topic description.
3.2. Constraint composition Looking at the licensePlate field of the Car class in Example 3.7, “Applying the CheckCase constraint”, we see three constraint annotations already. In complexer scenarios, where even more constraints could be applied to one element, this might become a bit confusing easily. Furthermore, if we had a licensePlate field in another class, we would have to copy all constraint declarations to the other class as well, violating the DRY principle. This problem can be tackled using compound constraints. In the following we create a new constraint annotation @ValidLicensePlate, that comprises the constraints @NotNull, @Size and @CheckCase: Example 3.9. Creating a composing constraint ValidLicensePlate package com.mycompany; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; @NotNull @Size(min = 2, max = 14) @CheckCase(CaseMode.UPPER) @Target( { METHOD, FIELD, ANNOTATION_TYPE }) @Retention(RUNTIME) @Constraint(validatedBy = {}) @Documented public @interface ValidLicensePlate { String message() default "{com.mycompany.constraints.validlicenseplate}"; Class [] groups() default {}; Class [] payload() default {}; } To do so, we just have to annotate the constraint declaration with its comprising constraints (btw. that's exactly why we allowed annotation types as target for the @CheckCase annotation). As no additional validation is required for the @ValidLicensePlate annotation itself, we don't declare a validator within the @Constraint meta annotation. Using the new compound constraint at the licensePlate field now is fully equivalent to the previous version, where we declared the three constraints directly at the field itself: Example 3.10. Application of composing constraint ValidLicensePlate package com.mycompany; public class Car { @ValidLicensePlate private String licensePlate; //... } The set of ConstraintViolations retrieved when validating a Car instance will contain an entry for each violated composing constraint of the @ValidLicensePlate constraint. If you rather prefer a single ConstraintViolation in case any of the composing constraints is violated, the @ReportAsSingleViolation meta constraint can be used as follows: Example 3.11. Usage of @ReportAsSingleViolation //... @ReportAsSingleViolation public @interface ValidLicensePlate { String message() default "{com.mycompany.constraints.validlicenseplate}"; Class [] groups() default {}; Class [] payload() default {}; }