1

在编写自定义约束时,一个验证器实现可以验证多个注释。例如,我有几个注释,它们规定了不同的@size 注释,但我希望它们都指向同一个验证器类,该验证器类进行一些全局检查,即所有都必须匹配某个正则表达式。据我所见,该实现采用一种注释类型。

一个注解

@Target( { METHOD, FIELD, ANNOTATION_TYPE, TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {UCNValidator.class})
@Documented
@Size(min = 9, max = 9, message = "{exactlength}")
public @interface UCN {

    String message() default "{invalidFormat}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String fieldName() default "ucn";

}

验证者

public class UCNValidator implements ConstraintValidator<UCN, String>
{

    private String pattern = "[a-zA-Z].*";
    private String fieldName;

    @Override
    public void initialize( UCN constraintAnnotation )
    {
        this.fieldName = constraintAnnotation.fieldName();
    }

    @Override
    public boolean isValid( String value, ConstraintValidatorContext constraintValidatorContext )
    {

        if ( value != null )
        {
            if ( !value.matches(pattern) )
            {
                //do some stuff
                return false;
            }

        }

        return true;

    }
4

1 回答 1

0

There doesn't seem to be a way to access other values from an object when validating one of its properties. The solution I use is to put the annotation on the class, then the validator will get the entire object in to validate against, and you can access just the info you need to perform the validation.

Here's one I wrote to compare two different properties of an object against each other:

@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = LessThanValidator.class)
@Documented
public @interface LessThan {

    String message() default "{com.bullethq.constraints.LessThan}";

    String bigValueProperty();

    String littleValueProperty();

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

Then the validator class is:

public class LessThanValidator implements ConstraintValidator<LessThan, Object> {

    private LessThan constraint;

    public void initialize(LessThan constraintAnnotation) {
        constraint = constraintAnnotation;
    }

    public boolean isValid(Object object, ConstraintValidatorContext cvc) {
        Object bigValue = getValue(object, constraint.bigValueProperty());
        Object littleValue = getValue(object, constraint.littleValueProperty());

        // If one of the values is null, then we do not perform validation.
        if (bigValue == null || littleValue == null) {
            return true;
        }

        if (bigValue instanceof Comparable && littleValue instanceof Comparable) {
            boolean valid = ((Comparable<Object>) bigValue).compareTo(littleValue) > 0;
            if (!valid) {
                // If the values are not valid, then build a custom violations which has the correct path in it.
                cvc.buildConstraintViolationWithTemplate(cvc.getDefaultConstraintMessageTemplate())
                        .addNode(constraint.littleValueProperty())
                        .addConstraintViolation().disableDefaultConstraintViolation();
            }
            return valid;
        }
        throw new IllegalArgumentException("Properties " + constraint.bigValueProperty() + " and " + constraint.littleValueProperty() + " both need to be comparable in " + object.getClass());
    }
}

The getValue() method is just a static method using reflection to get the value from the object.

于 2012-04-13T12:38:20.977 回答