14

enumフィールド付きのシンプルな豆があります

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

enum TestEnum{
  A, B, C, D
}

BeanValidationを使用して検証したいと思いtestFieldます。具体的には、A値とB値のみが許可されていることを確認したいと思います(特定のcalidation gropusに対して)。列挙型がJSR303(@Patternバリデーターを使用しようとしていた)で処理されていないか、間違った方法で何かを実行しているようです。

例外が発生しています:

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

カスタムバリデーターを作成せずに列挙型フィールドを検証する方法はありますか?

4

3 に答える 3

8

いくつかの理由で列挙がサポートされていないため、この制限は単純な文字列ベースのバリデーターで簡単に処理できます。

バリデーター:

/**
 * 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はApacheCommonsライブラリを使用します。高度な強制入力方式は、このバリデーターの柔軟性をさらに高めます。

別の方法として、配列の代わりに単一の文字列属性を使用し、区切り文字で分割することもできます。これは、配列が出力されないため、エラーメッセージの値も適切に出力しますが、null値の処理は次の場合に問題になる可能性があります。String.valueOf(...)

于 2013-09-19T22:36:13.423 に答える
7

testFieldに制約を設定する場合は、カスタムバリデーターが必要です。デフォルトのものはどれも列挙型を処理しません。

回避策として、列挙型の文字列値を返すgetterメソッドを追加できます。

public class TestBean{
   private TestEnum testField;
   //getters + setters

   @Pattern(regexp = "A|B") //does not work
   private String getTestFieldName() {
       return testField.name();
   }
}

ただし、カスタムバリデーターはおそらくよりクリーンなソリューションです。

于 2012-05-04T14:00:12.147 に答える
5

私の実用的なソリューションを共有したいと思います:

@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;
    }
于 2018-09-20T20:42:50.860 に答える