Spring Custom Annotation Validation with multiple field

后端 未结 2 1627
野趣味
野趣味 2021-01-02 19:06

A little greedy question here, hope this one could also help others who want to know more about annotation validation

I am currently studying Spring, and for now, I

2条回答
  •  离开以前
    2021-01-02 19:28

    For this you can use a type level annotation only because a field level annotation has no access to other fields!

    I did something similar to allow a choice validation (exactly one of a number of properties has to be not null). In your case the @AllOrNone annotation (or whatever name you prefer) would need an array of field names and you will get the whole object of the annotated type to the validator:

    @Target(ElementType.TYPE)
    @Retention(RUNTIME)
    @Documented
    @Constraint(validatedBy = AllOrNoneValidator.class)
    public @interface AllOrNone {
        String[] value();
    
        String message() default "{AllOrNone.message}";
        Class[] groups() default {};
        Class[] payload() default {};
    }
    
    public class AllOrNoneValidator implements ConstraintValidator {
        private static final SpelExpressionParser PARSER = new SpelExpressionParser();
        private String[] fields;
    
        @Override
        public void initialize(AllOrNone constraintAnnotation) {
            fields = constraintAnnotation.value();
        }
    
        @Override
        public boolean isValid(Object value, ConstraintValidatorContext context) {
            long notNull = Stream.of(fields)
                    .map(field -> PARSER.parseExpression(field).getValue(value))
                    .filter(Objects::nonNull)
                    .count();
            return notNull == 0 || notNull == fields.length;
        }
    }
    

    (As you said you use Spring I used SpEL to allow even nested fields access)

    Now you can annotate your Subscriber type:

    @AllOrNone({"birthday", "confirmBirthday"})
    public class Subscriber {
        private String name;
        private String email;
        private Integer age;
        private String phone;
        private Gender gender;
        private Date birthday;
        private Date confirmBirthday;
        private String birthdayMessage;
        private Boolean receiveNewsletter;
    }
    

提交回复
热议问题