After learning about Hibernate Custom Validators, it has given me an interest in one topic, could I possibly create one base annotation wherein I could set which Validator to use?
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = validator().class)
public @interface CustomAnnotation {
    public String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    Class<? extends ConstraintValidator<? extends CustomAnnotation, Serializable>> validator();
}
So that I could use @CustomAnnotation in this manner
@CustomAnnotation(validator = CustomConstraintValidator.class, message = "validationMessage")
private Object fieldName;
                I would not recommend it but you can do it roughly this way:
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = GenericValidatorBootstrapperValidator.class)
public @interface CustomAnnotation {
    public String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
    Class<? extends ConstraintValidator<? extends CustomAnnotation, Serializable>> validator();
}
public class GenericValidatorBootstrapperValidator implements ConstraintValidator<CustomAnnotation, Object> {
    private final ConstraintValidator validator;
    @Override
    public void initialize(CustomAnnotation constraintAnnotation) {
        Class<? extends ConstraintValidator> validatorClass = constraintAnnotation.validator();
        validator = validatorClass.newInstance();
        validator.initialize( ... ); //TODO with what?
    }
    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        return validator.isValid(value, context);
    }
}
But again, prefer specific annotations, they are more expressive.
After your comment, I think what you want is to be able to set different validators based on the return type of the property
@CustomAnnotation
List<String> foo;
@CustomAnnotation
Table bar;
If that's the case, add several validators implementations in the @Constraint annotation.
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {ListValidatorImpl.class, TableValidatorImpl.class, ...})
public @interface CustomAnnotation {
    public String message();
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
public class ListValidatorImpl implements ConstraintValidator<CustomAnnotation, List> {
    @Override
    public boolean isValid(List value, ConstraintValidatorContext context) {
    }
}
public class TableValidatorImpl implements ConstraintValidator<CustomAnnotation, Table> {
    @Override
    public boolean isValid(Table value, ConstraintValidatorContext context) {
    }
}
You can even link a contraint annotation with an implementation via the META/validation.xml file
<constraint-mappings
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.1.xsd"
    xmlns="http://jboss.org/xml/ns/javax/validation/mapping" version="1.1">
    <constraint-definition annotation="org.mycompany.CustomAnnotation">
        <validated-by include-existing-validators="true">
            <value>org.mycompany.EnumCustomValidatorImpl</value>
        </validated-by>
    </constraint-definition>
</constraint-mappings>
If you need something more flexible, I think my initial proposal would work. In the GenericValidatorBootstrapperValidator isValid method, you could call the right validator instance based on the object type of the value parameter (via instanceof for example).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With