Reputation: 4805
I would like to create a custom constraint @LengthIfNotBlank(min=,max=)
based on Hibernates @Length
constraint:
@Target( { METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = LengthIfNotBlankValidator.class)
@Documented
public @interface LengthIfNotBlank {
String message() default "{com.mycompany.LengthIfNotBlank}";
Class<? extends Payload>[] payload() default {};
int max() default Integer.MAX_VALUE;
Class<?>[] groups() default {};
int min() default 0;
}
public class LengthIfNotBlankValidator extends LengthValidator {
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
return StringUtils.isBlank(value) || super.isValid(value, constraintValidatorContext);
}
}
Exception:
[java] javax.validation.ValidationException: Unable to initialize com.example.constraints.LengthIfNotBlankValidator
[java] Caused by: java.lang.ClassCastException: $Proxy32 cannot be cast to org.hibernate.validator.constraints.Length
UPDATE
Still getting this exception :-(
public class LengthIfNotBlankValidator extends LengthValidator {
public void initialize(LengthIfNotBlank parameters) {
Map<String,Object> elements = new HashMap<String,Object>();
elements.put("message", parameters.message());
elements.put("payload", parameters.payload());
elements.put("groups", parameters.groups());
elements.put("min", parameters.min());
elements.put("max", parameters.max());
AnnotationDescriptor<Length> descriptor = AnnotationDescriptor.getInstance(Length.class, elements);
Length length = AnnotationFactory.create(descriptor);
super.initialize(length);
}
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
return StringUtils.isBlank(value) || super.isValid(value, constraintValidatorContext);
}
}
Upvotes: 5
Views: 6835
Reputation: 20579
I think you should not bother with that: Hibernate's LengthValidator
is really simple and whatever you do, you will end up with more code that if you had just reimplemented the code yourself like this:
public class LengthIfNotBlankValidator implements ConstraintValidator<LengthIfNotBlank, String> {
private int min;
private int max;
public void initialize(LengthIfNotBlank parameters) {
min = parameters.min();
max = parameters.max();
validateParameters();
}
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
if ( StringUtils.isBlank(value) ) {
return true;
}
int length = value.length();
return length >= min && length <= max;
}
private void validateParameters() {
if ( min < 0 ) {
throw new IllegalArgumentException( "The min parameter cannot be negative." );
}
if ( max < 0 ) {
throw new IllegalArgumentException( "The max parameter cannot be negative." );
}
if ( max < min ) {
throw new IllegalArgumentException( "The max cannot be less than the min." );
}
}
}
(This is just Hibernate's code adapted for your particular case).
Also, I don't think it would be possible to extend LengthValidator
while implementing ConstraintValidator<LengthIfNotBlank, String>
, which is mandatory for your validator.
Notice however that if you want to re-use unparameterized validators (or validators with constant parameters), you could simply annotate your validator with the re-used one (and maybe add @ReportAsSingleViolation
)
Upvotes: 1
Reputation: 242686
Since annotation types cannot be inherited, you should override initialize()
and pass an actual instance of type Length
to super.initialize()
.
Note that you cannot create an instance of annotation type directly, therefore you have to use something like AnnotationFactory
.
Also I'm not sure that compiler would allow you to do it due to type safety constraints. If it doesn't, use composition instead of inheritance (i.e. create a field of type LengthValidator
).
Upvotes: 2