Reputation: 1331
Let's consider the following example, I'm creating a custom bean validation constraint by means of a new annotation type:
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = MyAbstractOrInterfaceValidator.class)
@Documented
public @interface MyAnnotation {
String message() default "{}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
SomeClass value();
}
My question is: can MyBastractOrInterfaceValidator
class be an abstract class or an interface? How can I control which implementation of that interface or abstract class is used to validate an element the annotation is placed on?
Upvotes: 1
Views: 4005
Reputation: 18990
No, that's not possible. If you want to hide your validator implementations from the public constraint definitions, you have the following options:
validation.xml
, though.Upvotes: 2
Reputation: 15089
See http://docs.oracle.com/javaee/7/api/javax/validation/Constraint.html
First, note that validatedBy
is a Class<? extends ConstraintValidator<?,?>>[]
, that's an array, not a single class.
Second, there's no reason to use an interface or abstract class, because that class needs to be instantiated.
But, if you want to change the validator's implementation in the runtime, try using this:
public class MyValidator implements ConstraintValidator<MyAnnotation, String> {
//store the Class information in a static variable
private static Class<? extends ConstraintValidator<MyAnnotation, String>> implementationClass = MyValidatorOne.class;
//and change it by an accessor
public static void setImplementationClass(Class<? extends ConstraintValidator<MyAnnotation, String>> implClass) {
this.implementationClass = implClass;
}
//this delegate will do all the job
private final ConstraintValidator<MyAnnotation, String> implementation;
public MyValidator() {
implementation = implementationClass.newInstance();
}
@Override
void initialize(MyAnnotation constraintAnnotation) {
implementation.initialize(constraintAnnotation);
}
@Override
boolean isValid(T value, ConstraintValidatorContext context) {
return implementation.isValid(value, context);
}
}
somewhere in the code:
MyValidator.setImplementationClass(MyValidatorTwo.class);
But there's one problem. Most probably an instance of each validator is created once in the runtime for a single class - on the first validation call on object of that class. Implementation change will only take effect if done before that.
Other way is to store implementationClass
values in external class, like java.util.Properties or a class which picks available implementations with some priority.
Upvotes: 0