Play Framework - JSON Serialization Cyclic References (e.g. Files->User, User->Files) --> Stackoverflow

exception, json, parsing, playframework, stack-overflow

Solution

Okay, after hours of googling I found the solution: There is an annotation @JsonIgnore (import it from org.codehaus.jackson.annotate.JsonIgnore) which tells the JSON method to ignore this property.

EDIT: Digging further, the cleaner solution for dealing with cyclic references during JSON Serialization is to write a custom De- and Serializer. A very good post by Steve Hill can be found here: http://dev.sghill.net/2012/04/how-do-i-write-jackson-json-serializer.html

Problem

I've been playing around with the play framework for a couple of days now but came across one issue I can't solve: Suppose you have some "User" and "File" classes. Both reference each other and are persisted in the database with ebean (@ManyToOne, @OneToMany). Now when return a user as JSON I get a stackoverflow Error. Is this a bug in play or am I missing something? ``` @Entity public class File extends Model { private static final long serialVersionUID = 1L; @Id @GeneratedValue public Long id; @ManyToOne(cascade=CascadeType.ALL) public User author; } ``` ``` @Entity public class User extends Model { private static final long serialVersionUID = 1L; @Id @GeneratedValue public Long id; @OneToMany(mappedBy="author", cascade=CascadeType.ALL) public List<File> files; } ``` ``` import play.libs.Json; public class Users extends Controller { public static Result getJSON() { List<User> users = new Model.Finder<String, User>(String.class, User.class).all(); return ok(Json.toJson(users)); } } ``` Stacktrace: ``` org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> models.User["files"]->com.avaje.ebean.common.BeanList[0]->models.File["author"]-> . . . ->models.User["files"]) at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:164) ~[jackson-mapper-asl.jar:1.9.10] at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112) ~[jackson-mapper-asl.jar:1.9.10] at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446) ~[jackson-mapper-asl.jar:1.9.10] at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150) ~[jackson-mapper-asl.jar:1.9.10] at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112) ~[jackson-mapper-asl.jar:1.9.10] at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:72) ~[jackson-mapper-asl.jar:1.9.10] java.lang.StackOverflowError: null at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.7.0_45] at java.lang.ClassLoader.defineClass(ClassLoader.java:800) ~[na:1.7.0_45] at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.7.0_45] at java.net.URLClassLoader.defineClass(URLClassLoader.java:449) ~[na:1.7.0_45] at java.net.URLClassLoader.access$100(URLClassLoader.java:71) ~[na:1.7.0_45] at java.net.URLClassLoader$1.run(URLClassLoader.java:361) ~[na:1.7.0_45] ```

Original source