Play Framework: Binding and Validating Objects and Rendering JSON Output

Exclusive offer: get 50% off this eBook here
Play Framework Cookbook

Play Framework Cookbook — Save 50%

Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework

$26.99    $13.50
by Alexander Reelsen | August 2011 | Java Open Source

The Play framework is the new kid on the block of Java frameworks. By breaking the existing standards it tries not to abstract away from HTTP as with most web frameworks, but tightly integrates with it. This means quite a shift for Java programmers. Understanding the concepts behind this shift and its impact on web development with Java are crucial for fast development of Java web applications.

In the previous article by Alexander Reelsen, author of Play Framework Cookbook, we took a look at data validation using controllers.

In this article we will we will cover:

  • Binding objects using custom binders
  • Validating objects using annotations
  • Rendering JSON output

 

Play Framework Cookbook

Play Framework Cookbook

Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework

        Read more about this book      

(For more resources related to this subject, see here.)

Binding objects using custom binders

Read the Play documentation about object binding. As validation is extremely important in any application, it basically has to fulfill several tasks.

First, it should not allow the user to enter wrong data. After a user has filled a form, he should get a positive or negative feedback, irrespective of whether the entered content was valid or not. The same goes for storing data. Before storing data you should make sure that storing it does not pose any future problems as now the model and the view layer should make sure that only valid data is stored or shown in the application. The perfect place to put such a validation is the controller.

As a HTTP request basically is composed of a list of keys and values, the web framework needs to have a certain logic to create real objects out of this argument to make sure the application developer does not have to do this tedious task.

You can find the source code of this example in the chapter2/binder directory.

How to do it...

Create or reuse a class you want created from an item as shown in the following code snippet:

public class OrderItem {

@Required public String itemId;
public Boolean hazardous;
public Boolean bulk;
public Boolean toxic;
public Integer piecesIncluded;

public String toString() {
return MessageFormat.format("{0}/{1}/{2}/{3}/{4}", itemId,
piecesIncluded, bulk, toxic, hazardous);
}
}

Create an appropriate form snippet for the index.xml template:

#{form @Application.createOrder()}
<input type="text" name="item" /><br />
<input type="submit" value="Create Order">
#{/form}

Create the controller:

public static void createOrder(@Valid OrderItem item) {
if (validation.hasErrors()) {
render("@index");
}

renderText(item.toString());
}

Create the type binder doing this magic:

@Global
public class OrderItemBinder implements TypeBinder<OrderItem> {

@Override
public Object bind(String name, Annotation[] annotations, String
value,
Class actualClass) throws Exception {

OrderItem item = new OrderItem();
List<String> identifier = Arrays.asList(value.split("-", 3));

if (identifier.size() >= 3) {
item.piecesIncluded = Integer.parseInt(identifier.get(2));
}

if (identifier.size() >= 2) {
int c = Integer.parseInt(identifier.get(1));
item.bulk = (c & 4) == 4;
item.hazardous = (c & 2) == 2;
item.toxic = (c & 1) == 1;
}

if (identifier.size() >= 1) { item.itemId = identifier.get(0);
}

return item;
}
}

How it works...

With the exception of the binder definition all of the preceding code has been seen earlier. By working with the Play samples you already got to know how to handle objects as arguments in controllers. This specific example creates a complete object out of a simple String. By naming the string in the form value (<input …name="item" />) the same as the controller argument name (createOrder(@Valid OrderItem item)) and using the controller argument class type in the OrderItemBinder definition (OrderItemBinder implements TypeBinder<OrderItem>), the mapping is done.

The binder splits the string by a hyphen, uses the first value for item ID, the last for piìesIncluded, and checks certain bits in order to set some Boolean properties.

By using curl you can verify the behavior very easily as shown:

curl -v -X POST --data "item=Foo-3-5" localhost:9000/order

Foo/5/false/true/true

Here Foo resembles the item ID, 5 is the piecesIncluded property, and 3 is the argument means that the first two bits are set and so the hazardous and toxic properties are set, while bulk is not.

There's more...

The TypeBinder feature has been introduced in Play 1.1 and is documented at http://www.playframework.org/documentation/1.2/controllers#custombinding.

Using type binders on objects

Currently, it is only possible to create objects out of one single string with a TypeBinder. If you want to create one object out of several submitted form values you will have to create your own plugin for this as workaround. You can check more about this at:

http://groups.google.com/group/play-framework/browse_thread/thread/62e7fbeac2c9e42d

Be careful with JPA using model classes

As soon as you try to use model classes with a type binder you will stumble upon strange behavior, as your objects will always only have null or default values when freshly instanced. The JPA plugin already uses a binding and overwrites every binding you are doing.

Play Framework Cookbook Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework
Published: August 2011
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources related to this subject, see here.)

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;

Rendering JSON output

As soon as a web application consists of a very fast frontend, no or seldom complete page reloads occur. This implies a complete rendering by the browser, which is one of the most time consuming tasks when loading a webpage in the browser. This means you have to get the data as fast as possible to the client. You can either send them as pre-rendered HTML, XML, or JSON format. Sending the data in either JSON or XML means the application on the browser side can render the data itself and decide how and when it should be displayed. This means your application should be able to create JSON or XML-based responses.

As JSON is quite popular, this example will not only show you how to return the JSON representation of an entity, but also how to make sure sensitive data such as a password will not get sent to the user.

Furthermore some hypermedia content will be added to the response, like an URL where more information can be found.

You can find the source code of this example in the chapter2/json-render-properties directory.

Getting ready

Beginning with a test is always a good idea:

public class JsonRenderTest extends FunctionalTest {

@Test
public void testThatJsonRenderingWorks() {
Response response = GET("/user/1");
assertIsOk(response);

User user = new Gson().fromJson(getContent(response), User.
class);
assertNotNull(user);
assertNull(user.password);
assertNull(user.secrets);
assertEquals(user.login, "alex");
assertEquals(user.address.city, "Munich");
assertContentMatch("\"uri\":\"/user/1\"", response);
}
}

This expects a JSON reply from the request and parses it into a User instance with the help of gson, a JSON library from Google, which is also used by Play for serializing. As we want to make sure that no sensitive data is sent, there is a check for nullified values of password and secrets properties. The next check goes for a user property and for a nested property inside another object. The last check has to be done by just checking for an occurrence of the string, because the URL is not a property of the user entity and is dynamically added by the special JSON serializing routine used in this example.

How to do it...

Create your entities first. This example consists of a user, an address, and a SuperSecretData entity:

@Entity
public class User extends Model {

@SerializedName("userLogin")
public String login;
@NoJsonExport
public String password;
@ManyToOne
public Address address;
@OneToOne
public SuperSecretData secrets;

public String toString() {
return id + "/" + login;
}
}

@Entity
public class Address extends Model {
public String street;
public String city;
public String zip;
}

@Entity
public class SuperSecretData extends Model {
public String secret = "foo";
}

The controller is simple as well:

public static void showUser(Long id) {
User user = User.findById(id);
notFoundIfNull(user);
renderJSON(user, new UserSerializer());
}

The last and most important part is the serializer used in the controller above:

public class UserSerializer implements JsonSerializer<User> {

public JsonElement serialize(User user, Type type,
JsonSerializationContext context) {
Gsongson = new GsonBuilder()
.setExclusionStrategies(new LocalExclusionStrategy())
.create();

JsonElementelem = gson.toJsonTree(user);
elem.getAsJsonObject().addProperty("uri", createUri(user.id));
return elem;
}

private String createUri(Long id) {
Map<String,Object> map = new HashMap<String,Object>();
map.put("id", id);
return Router.reverse("Application.showUser", map).url;
}

public static class LocalExclusionStrategy implements
ExclusionStrategy {

public booleanshouldSkipClass(Class<?>clazz) {
return clazz == SuperSecretData.class;
}

public booleanshouldSkipField(FieldAttributes f) {
return f.getAnnotation(NoJsonExport.class) != null;
}
}
}

How it works...

The entities used in this example are simple. The only differences are the two annotations in the User entity. First there is a SerializedNamed annotation, which uses the annotation argument as field name in the json output – this annotation comes from the gson library. The @NoJsonExport annotation has been specifically created in this example to mark fields that should not be exported like a sensitive password field in this example. The address field is only used as an example to show how many-to-many relations are serialized in the JSON output.

As you might guess, the SuperSecretData class should mark the data as secret, so this field should not be exported as well. However, instead of using an annotation, the functions of the Google gson library will be utilized for this.

The controller call works like usual except that the renderJson() method gets a specific serializer class as argument to the object it should serialize.

The last class is the UserSerializer class, which is packed with features, although it is quite short. As the class implements the JsonSerializer class, it has to implement the serialize() method. Inside of this method a gson builder is created, and a specific exclusion strategy is added. After that the user object is automatically serialized by the gson object. Lastly another property is added. This property is the URI of the showUser() controller call, in this case something like /user/{id} . You can utilize the Play internal router to create the correct URL.

The last part of the serializer is the ExclusionStrategy, which is also a part of the gsonserializer. This strategy allows exclusion of certain types of fields. In this case the method shouldSkipClass() excludes every occurrence of the SuperSecretData class, where the method shouldSkipFields() excludes fields marked with the @NoJsonExport annotation.

There's more...

If you do not want to write your own JSON serializer you could also create a template ending with .json and write the necessary data like in a normal HTML template. However there is no automatic escaping, so you would have to take care of that yourself.

More about Google gson

Google gson is a pretty powerful JSON library. Once you get used to it and learn to utilize its features it may help you to keep your code clean. It has very good support for specific serializers and deserializers, so make sure you check out the documentation before trying to build something for yourself. Read more about it at http://code.google.com/p/google-gson/.

Alternatives to Google gson

Many developers do not like the gson library at all. There are several alternatives. There is a nice example of how to integrate FlexJSON. Check it out at http://www.lunatechresearch.com/archives/2011/04/20/play-framework-better-jsonserialization-flexjson.

Summary

In this article we took a look at binding objects using custom binders, validating objects using annotations, and rendering JSON output.


Further resources related to this subject:


Play Framework Cookbook Over 60 incredibly effective recipes to take you under the hood and leverage advanced concepts of the Play framework
Published: August 2011
eBook Price: $26.99
Book Price: $44.99
See more
Select your format and quantity:

About the Author :


Alexander Reelsen

Alexander Reelsen is a software engineer living in Munich, Germany, where he has been working on different software systems, for example a touristic booking engine, a campaign management and messaging platform and a b2b ecommerce portal. He has been using the play framework since 2009 and was immediately astonished by the sheer simplicity of this framework, while still being pure java. Other interests include scaling shared-nothing web architectures and nosql databases.

Being rather a system engineer most of the time when he started playing around with Linux at the age of 14, Alexander got to know software engineering during his studies and decided web applications are more interesting than system administration.

If not doing something hacky, he enjoys playing a good game of basketball or streetball.
Sometimes he even twitters at http://twitter.com/spinscale and can be reached anytime at alexander@reelsen.net

Books From Packt


Agile Web Application Development with Yii1.1 and PHP5
Agile Web Application Development with Yii1.1 and PHP5

Python 3 Web Development Beginner's Guide
Python 3 Web Development Beginner's Guide

AJAX and PHP: Building Modern Web Applications 2nd Edition
AJAX and PHP: Building Modern Web Applications 2nd Edition

Building Dynamic Web 2.0 Websites with Ruby on Rails
Building Dynamic Web 2.0 Websites with Ruby on Rails

Google Web Toolkit 2 Application Development Cookbook
Google Web Toolkit 2 Application Development Cookbook

Ext GWT 2.0: Beginner's Guide
Ext GWT 2.0: Beginner's Guide

Grok 1.0 Web Development
Grok 1.0 Web Development

Apache Wicket Cookbook
Apache Wicket Cookbook


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
5
q
a
V
a
x
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software