JSR-303 Bean Validation for enum fields

前端 未结 3 655
南笙
南笙 2021-02-05 19:40

I have a simple bean with enum field

public class TestBean{
   @Pattern(regexp = \"A|B\") //does not work
   private TestEnum testField;
   //getter         


        
相关标签:
3条回答
  • 2021-02-05 20:04

    If you want to put the constraint on testField you need a custom validator. None of the default ones handle enums.

    As a workaround you could add a getter method which returns the string value of the enum

    public class TestBean{
       private TestEnum testField;
       //getters + setters
    
       @Pattern(regexp = "A|B") //does not work
       private String getTestFieldName() {
           return testField.name();
       }
    }
    

    A custom validator is probably the cleaner solution though.

    0 讨论(0)
  • 2021-02-05 20:26

    I'd like to share my working solution:

    @Documented
    @Constraint(validatedBy = { EnumValueValidator.class })
    @Retention(RetentionPolicy.RUNTIME)
    
    @Target({ 
        ElementType.ANNOTATION_TYPE, 
        ElementType.CONSTRUCTOR,
        ElementType.FIELD, 
        ElementType.METHOD, 
        ElementType.PARAMETER 
    })
    
    public @interface EnumValue
    {
        public abstract String                             message() default "{validation.enum.message}";
    
        public abstract Class<?>[]                         groups()  default {};
    
        public abstract Class<? extends Payload>[]         payload() default {};
    
        public abstract Class<? extends java.lang.Enum<?>> enumClass();
    }
    
    public class EnumValueValidator implements ConstraintValidator<EnumValue, Object>
    {
        private Object[] enumValues;
    
        @Override
        public void initialize(final EnumValue annotation)
        {
            enumValues = annotation.enumClass().getEnumConstants();
        }
    
        @Override
        public boolean isValid(final Object value, final ConstraintValidatorContext context)
        {
            if (null != value) {
                String contextValue = value.toString();
    
                for (Object enumValue : enumValues) {
                    if (enumValue.toString().equals(contextValue)) {
                        return true;
                    }
                }
            }
    
            return false;
        }
    
    0 讨论(0)
  • 2021-02-05 20:28

    Since for some reasons enumerations are not supported this restriction could be simply handled by a simple String based Validator.

    Validator:

    /**
     * Validates a given object's String representation to match one of the provided
     * values.
     */
    public class ValueValidator implements ConstraintValidator<Value, Object>
    {
        /**
         * String array of possible enum values
         */
        private String[] values;
    
        @Override
        public void initialize(final Value constraintAnnotation)
        {
            this.values = constraintAnnotation.values();
        }
    
        @Override
        public boolean isValid(final Object value, final ConstraintValidatorContext context)
        {
            return ArrayUtils.contains(this.values, value == null ? null : value.toString());
        }
    }
    

    Interface:

    @Target(value =
    {
        ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER
    })
    @Retention(RetentionPolicy.RUNTIME)
    @Constraint(validatedBy =
    {
        ValueValidator.class
    })
    @Documented
    public @interface Value
    {
        public String message() default "{package.Value.message}";
    
        Class<?>[] groups() default
        {};
    
        Class<? extends Payload>[] payload() default
        {};
    
        public String[] values() default
        {};
    }
    

    Validator uses apache commons library. An advanced coerce to type method would enhance the flexibility of this validator even further.

    An alternative could use a single String attribute instead of an array and split by delimiter. This would also print values nicely for error-message since arrays are not being printed, but handling null values could be a problem using String.valueOf(...)

    0 讨论(0)
提交回复
热议问题