Presentation Layer Validation: Bean Validation Within JSF 2.0
Autor: Diego Borges | Publicado: 2011-09-22T18:29:00-03:00

This week, at Elsa Development, we’ve been implementing some customized validators using Bean Validation API. Everything was going fine, until the shadows of Murphy appear. OK, putting aside the drama, a few validators have been implemented successfully, passing all tests, all of them but one...

The Problem

Two constraints were created and for each one, a validator was implemented (which executes the validation logic). Both constraints were used at field-level on JPA entities, the Username and FloatRange constraints were annotated on fields of type string and float, respectively. However, just the Username constraint worked.. Hereunder you can take a look at the implemented code, or part of it :)


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UsernameValidator.class)
@Target({
    ElementType.METHOD,
    ElementType.FIELD,
    ElementType.ANNOTATION_TYPE
})
public @interface Username {
    String message() default "{constraint.username.invalid}";
    Class&lt;? extends Payload&gt;[] payload() default {};
    Class&lt;?&gt;[] groups() default {};
}
Code 1. The working constraint.



public class UsernameValidator
        implements ConstraintValidator&lt;Username, String&gt; {
    @Override
    public void initialize(Username annotation) {}

    @Override
    public boolean isValid(String value,
            ConstraintValidatorContext context) {
        // validation logic ommited
    }
}
Code 2. The validation for @Username constraint.



@Documented
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = FloatRangeValidator.class)
@Target({
    ElementType.METHOD,
    ElementType.FIELD,
    ElementType.ANNOTATION_TYPE
})
public @interface FloatRange {

    String message() default "{constraint.range}";
    Class&lt;? extends Payload&gt;[] payload() default {};
    Class&lt;?&gt;[] groups() default {};
    float min();
    float max();
}
Code 3. The “murphyfied” constraint (i.e. did not work).



public class FloatRangeValidator
        implements ConstraintValidator&lt;FloatRange, Float&gt; {
    private float min;
    private float max;
 
    @Override
    public void initialize(FloatRange annotation) {
        this.min = annotation.min();
        this.max = annotation.max();
    }

    @Override
    public boolean isValid(Float value,
            ConstraintValidatorContext context) {
        // validation logic ommited
    }
}
Code 4. The “murphyfied” constraint.


The Solution

After a lot of googling and force brute tests... A co worker (Marcelo Yamashita) came with the solution. He tried to use the @FloatRange constraint at property-level, man... that worked! Then, reading more carefully the Hibernate Validator documentation, more specifically the item 2.1.1. Field-level constraints, i noticed the note that says:




Static fields and properties cannot be validated.

&nbsp;



Well, if i've got it right, by properties it means POJO fields which have getter/setter, or not? If so, then houston, we have a problem... both target annotated fields, belong to JPA entities thus, they have getters and setters! It doesn’t make them properties? Anyway, the workaround rocks, but if you have any idea about the why this happens, please, feel free to share it with the world :)