Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Wednesday, August 31, 2011

Avoiding Circular References in the Play! Framework

If you're producing JSON in a Play! Framework app, watch for circular references caused by bi-directional JPA relationships.  Use a custom JsonSerializer to break the cycle.

Bi-Directional Relationships

A bi-directional relationship is very common in JPA, the persistence architecture used in the Play! Framework.  Most @ManyToOnes complement a @OneToMany allowing for different navigation paths.  For example, this @Entity Topic may classify one or more Tutorials.
@OneToMany Part of Bi-Directional Relationship
 The @OneToMany lets the application present a Topic and easily retrieve the related Tutorials.  The relationship is bi-directional, so there is a corresponding reference to Topic from Tutorial.  This allows a screen showing a Tutorial to easily display its Topic.

@ManyToOne Part of Bi-Directional Relationship
 Using a Play! Controller, render these structures in JSON by calling "renderJSON()" and passing in an @Entity retrieved by a find operation.  This will work if the @Entity doesn't contain bi-directional relationships.  If the @Entity does have this type of relationship, you'll get the following error message.
Circular Reference Error
The error was generated rendering a third @Entity, "TextualProc", that references Tutorial.

Entity that Initiated Reference Error

The error is generated because the default JSON serializer can't resolve the circular reference.  For a good explanation of the default behavior and an alternative resolution to the above error, follow this link to Lunatech Research.

JsonSerializer

To resolve the circular reference error, create your own JsonSerializer.  Your custom JsonSerializer should restrict the navigation to a single path.  For example, this JsonSerializer outputs an @Entity TextualProc and its child records Step.  TextualProc and Step have a bi-directional relationship, but it isn't being considered as the for loop navigates one-way.

A JsonSerializer
And the results of making a call using this serializer are

JSON Result

Controller

Instead of using a renderJSON() call with a single object argument in the Play! Controller, the call will use an additional argument for the JsonSerializer.  Here is a method from a Controller.

Controller Method Rendering JSON
 If you have a simple @Entity, specifically one without a bi-directional relationship, you can use the default JSON serialization to render the entity without extra classes.  However, for the more complex entity, create a class that implements a JsonSerializer and use that in your Play! Controller to avoid a circular reference.


1 comment: