In Play 2.0, the validation framework extends beyond the actual validation of the data as it reaches to:
- Annotations - to easily declare validation contraints using the '@' sign
- Validators - which actually implements to logic behind the validation
- Messages - to display parametrized error messages (i18 compliant)
- Finally, HTML helpers - that glue all the previous together
The HTML Helpers are something new to Play 2.0. In 1.x, Play was already pretty good at enforcing a well defined validation framework. It was powerful and easy to use. Yet we still had to wire the HTML form and the validation framework together. This could be a little confusing to the beginner.
With Play 2.0, this is now done automatically.
But let's focus on the answer and provide some guidance: We will create an AllUpperCase validator, that generates an error either when:
- the input is not a String
- the input is empty
- one of the characters is lower-case.
The validator
package myvalidators;
import javax.validation.*;
public class AllUpperCaseValidator
extends play.data.validation.Constraints.Validator<Object>
implements ConstraintValidator<AllUpperCase, Object> {
/* Default error message */
final static public String message = "error.alluppercase";
/**
* Validator init
* Can be used to initialize the validation based on parameters
* passed to the annotation.
*/
public void initialize(AllUpperCase constraintAnnotation) {}
/**
* The validation itself
*/
public boolean isValid(Object object) {
if(object == null)
return false;
if(!(object instanceof String))
return false;
String s = object.toString();
for(char c : s.toCharArray()) {
if(Character.isLetter(c) && Character.isLowerCase(c))
return false;
}
return true;
}
/**
* Constructs a validator instance.
*/
public static play.data.validation.Constraints.Validator<Object> alluppercase() {
return new AllUpperCaseValidator();
}
}
The first thing you may notice is the import: Play 2.0 indeed complies with JSR 303 - Bean Validation Framework. In this context, the validator needs to implement ConstraintValidator. Which in our case translates into the annotation as class AllUpperCase
(which we will introduce in a minute) and T as a generic Object
.
The validator is straighforward:
We defined the method public boolean isValid(Object object) that returns a boolean, if true the validation passed. There is also an message id and a method that instanciates the validator.
The Annotation
The class below defines an annotation named @AllUpperCase
which takes no parameters but enforces the validation defined previously. Providing details related to the annotation framework is outside the scope of this post.
package myvalidators;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import javax.validation.*;
@Target({FIELD})
@Retention(RUNTIME)
@Constraint(validatedBy = AllUpperCaseValidator.class)
@play.data.Form.Display(name="constraint.alluppercase")
public @interface AllUpperCase {
String message() default AllUpperCaseValidator.message;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Note how the anotation glues to the other pieces of the puzzle.
@Constraint
, a JSR 303 annotation, links to the validator
@play.data.Form.Display
, links the annotation to the play html helpers. Note that the name is important: we are defining a constraint named alluppercase. Play uses this information to call the method public static play.data.validation.Constraints.Validator<Object> alluppercase()
on the Validator.
- Finally note that the default message is set within the anotation interface.
Usage
We now have our custom validator and annotation
import myvalidators.*;
public static class MyData {
@AllUpperCase
public String name;
}
Describing the usage is outside the scope of this post, please find a working sample at this URL
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…