【问题标题】:JSR-303 Bean Validation for enum fields枚举字段的 JSR-303 Bean 验证
【发布时间】:2012-05-04 08:19:28
【问题描述】:

我有一个带有enum 字段的简单bean

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

enum TestEnum{
  A, B, C, D
}

我想使用 Bean Validation 来验证 testField。具体来说,我想确保只允许 A 和 B 值(对于特定的校准组)。似乎 JSR 303 没有处理枚举(我试图使用 @Pattern 验证器)或者我做错了事。

我遇到了异常:

javax.validation.UnexpectedTypeException: No validator could be found for type: packagename.TestEnum

有什么方法可以在不编写自定义验证器的情况下验证枚举字段?

【问题讨论】:

    标签: jakarta-ee java-ee-6 bean-validation


    【解决方案1】:

    由于某些原因不支持枚举,这个限制可以简单地由一个简单的基于字符串的验证器来处理。

    验证器:

    /**
     * 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());
        }
    }
    

    界面:

    @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 使用 apache 公共库。高级强制类型方法将进一步增强此验证器的灵活性。

    另一种方法可以使用单个字符串属性而不是数组并按分隔符拆分。这也可以很好地打印错误消息的值,因为没有打印数组,但是使用String.valueOf(...)处理空值可能是一个问题

    【讨论】:

      【解决方案2】:

      如果你想对 testField 施加约束,你需要一个自定义验证器。没有一个默认的处理枚举。

      作为一种解决方法,您可以添加一个 getter 方法,该方法返回枚举的字符串值

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

      不过,自定义验证器可能是更简洁的解决方案。

      【讨论】:

        【解决方案3】:

        我想分享我的工作解决方案:

        @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;
            }
        

        【讨论】:

          猜你喜欢
          • 2015-01-10
          • 1970-01-01
          • 2013-11-23
          • 1970-01-01
          • 2011-07-24
          • 2011-01-31
          • 2011-10-23
          • 2016-06-21
          • 2012-05-12
          相关资源
          最近更新 更多