Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom validator in Play Framework 2.0?

Play 1.0 comes with a full featured validation framework base on http://oval.sourceforge.net/.

With the release of 2.0, my custom validators do not work anymore.

How does one create custom validator using Play Framework 2.0 ?

like image 331
Olivier Refalo Avatar asked Nov 13 '11 22:11

Olivier Refalo


People also ask

What is a custom validator?

The CustomValidator control is a separate control from the input control it validates, which allows you to control where the validation message is displayed. Validation controls always perform validation on the server.

What is Java validator?

public abstract class Validator extends Object. A processor that checks an XML document against Schema . A validator object is not thread-safe and not reentrant.


1 Answers

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

like image 104
Olivier Refalo Avatar answered Sep 20 '22 01:09

Olivier Refalo