Validating objects using annotations

Basic validation should be clear for you now. It is well-documented in the official documentation and shows you how to use the different annotations such as @Min, @Max, @Url, @Email, @InFuture, @InPast, or @Range. You should go a step forward and add custom validation. An often needed requirement is to create some unique string used as identifier. The standard way to go is to create a UUID and use it. However, validation of the UUID should be pretty automatic and you want to be sure to have a valid UUID in your models.

You can find the source code of this example in the chapter2/annotation-validation directory.

Getting ready

As common practice is to develop your application in a test driven way, we will write an appropriate test as first code in this recipe. In case you need more information about writing and using tests in Play, you should read http://www.playframework.org/documentation/1.2/test.

This is the test that should work:

public class UuidTest extends FunctionalTest {

    @Test
    public void testThatValidUuidWorks() {
        String uuid = UUID.randomUUID().toString();
        Response response = GET("/" + uuid);
        assertIsOk(response);
        assertContentEquals(uuid + " is valid", response);
    }

    @Test
    public void testThatInvalidUuidWorksNot() {
        Response response = GET("/absolutely-No-UUID");
        assertStatus(500, response);
    }
}

So whenever a valid UUID is used in the URL, it should be returned in the body and whenever an invalid UUID has been used, it should return HTTP error 500.

How to do it...

Add an appropriate configuration line to your conf/routes file:

GET     /{uuid}    Application.showUuid

Create a simple @UUID annotation, practically in its own annotations or validations package:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Constraint(checkWith = UuidCheck.class)
public @interface Uuid {
        String message() default "validation.invalid.uuid";
}

Create the appropriate controller, which uses the @Uuid annotation:

public class Application extends Controller {

    public static void showUuid(@Uuid String uuid) {
        if (validation.hasErrors()) {
            flash.error("Fishy uuid");
            error();
        }   

        renderText(uuid + " is valid");
    }   
}

Create the check, which is triggered by the validation. You might want to put it into the checks package:

public class UuidCheck extends AbstractAnnotationCheck<Uuid> {

    @Override
    public booleanisSatisfied(Object validatedObject, Object value, OValContext context, Validator validator)
    throws OValException {

        try {
            UUID.fromString(value.toString());
            return true;
        } catch (IllegalArgumentException e) {}

        return false;
    }
}

How it works...

When starting your application via play test and going to http://localhost:9000/@tests you should be able to run the UuidTest without problems.

Except the UuidCheck class, most of this here is old stuff. The Uuid annotation has two specialties. First it references the UuidCheck with a constraint annotation and second you can specify a message as argument. This message is used for internationalization.

The UuidCheck class is based on an Oval class. Oval is a Java library and used by the Play framework for most of the validation tasks and can be pretty easily extended as you can see here. All you need to implement is the isSatisfied() method. In this case it has tried to convert a String to a UUID. If it fails, the runtime exception thrown by the conversion is caught and false is returned, marking the check as invalid.

There's more...

The oval framework is pretty complex and the logic performed here barely scratches the surface. For more information about oval, check the main documentation at http://oval.sourceforge.net/.

Using the configure() method for setup

The AbstractAnnotationCheck class allows you to overwrite the configure(T object) method (where T is generic depending on your annotation). This allows you to set up missing annotation parameters with default data; for example, default values for translations. This is done by many of the already included Play framework checks as well.

Annotations can be used in models as well

Remember that the annotation created above may also be used in your models, so you can label any String as a UUID in order to store it in your database and to make sure it is valid when validating the whole object.

@Uuid public String registrationUuid;
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.170.63