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:
public class ConstrainedBean {
@CustomPassword
public String password;
}
//...
BeanDescriptor beanDescriptor = validator.getConstraintsForClass( ConstrainedBean.class );
This bean descriptor will contain a constrained property and you'd be able to get the expected 10
navigating through constraintDescriptor#composingConstraints
first to get to CustomString
and then to Size
.
When you are passing the CustomPassword.class
you are getting a metadata as if you are going to validate the instance of a CustomPassword.class
and at that point validator considers CustomString
as a class-level constraint and none of OverridesAttribute
from CustomPassword
are considered since beans do not override any constraint attributes.