I have a number of Java Annotation classes.
The idea is that developers/consumers of my project will use these annotations on fields inside their POJOs in order to describe each field.
Example relationship between these annotations: @CustomString -> @CustomPassword
Why is it that when I try to get the constraints on @CustomPassword using validator.getConstraintsForClass, the min does not contain the value specified inside CustomPassword i.e 10
I want to use:
@OverridesAttribute(constraint = CustomString.class, name = "min")
int min() default 10;
To override the value because I'd like developers to be able to create their own annotation classes that sit on top of CustomPassword and maybe provide their own overrides.
@CustomString sets @Size min and max constraints:
import java.lang.annotation.*;
import javax.validation.Constraint;
import javax.validation.OverridesAttribute;
import javax.validation.Payload;
import javax.validation.constraints.Size;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Size
@Constraint(validatedBy = {})
public @interface CustomString {
@OverridesAttribute(constraint = Size.class, name = "min")
int min() default 0;
@OverridesAttribute(constraint = Size.class, name = "max")
int max() default Integer.MAX_VALUE;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "{org.example.annotation.base.string}";
}
@CustomPassword which contains a reference to @CustomString, and attempts to override the min from @CustomString:
import org.ecample.annotation.base.CustomString;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.OverridesAttribute;
import javax.validation.Payload;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
@CustomString
@Constraint(validatedBy = {})
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface CustomPassword {
@OverridesAttribute(constraint = CustomString.class, name = "min")
int min() default 10;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
String message() default "{org.example.annotation.extended.password}";
}
Why is it that when I run:
Class<?> klass = CustomPassword.class;
Validator validator =
Validation.byDefaultProvider()
.configure()
.messageInterpolator(new ParameterMessageInterpolator())
.buildValidatorFactory().getValidator();
BeanDescriptor beanDescriptor = validator.getConstraintsForClass(klass);
The constraintDescriptors inside BeanDescriptor still has a min of 0, shouldn't it have been overridden by the min inside CustomPassword and be set to 10?
((BeanDescriptorImpl)beanDescriptor).constraintDescriptors.iterator().next().annotationDescriptor
@c.c.c.m.t.a.b.CustomString(groups=[Ljava.lang.Class;@3d9f0a5, max=2147483647, message={org.example.annotation.base.string}, min=0, payload=[Ljava.lang.Class;@1953bc95)
The problem is that you are trying to look at the bean descriptor of a constraint annotation itself. The
Validator#getConstraintsForClass(..)is intended to provide the metadata for the bean. If you'd try something like:This bean descriptor will contain a constrained property and you'd be able to get the expected
10navigating throughconstraintDescriptor#composingConstraintsfirst to get toCustomStringand then toSize.When you are passing the
CustomPassword.classyou are getting a metadata as if you are going to validate the instance of aCustomPassword.classand at that point validator considersCustomStringas a class-level constraint and none ofOverridesAttributefromCustomPasswordare considered since beans do not override any constraint attributes.