Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSR-303 Bean Validation for enum fields

I have a simple bean with enum field

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

enum TestEnum{
  A, B, C, D
}

I would like to validate testField using Bean Validation. Specifically I would like to make sure that only A and B values are allowed (for a particular calidation gropus). It seems that enums are not handled JSR 303 (I was trying to use @Pattern validator) or I am doing something in a wrong way.

I am getting exception:

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

Is there any way to validate enum fields without writing custom validator?

like image 418
Piotr Kochański Avatar asked May 04 '12 08:05

Piotr Kochański


2 Answers

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(...)

like image 149
djmj Avatar answered Oct 05 '22 17:10

djmj


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.

like image 42
Hardy Avatar answered Oct 05 '22 15:10

Hardy