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]
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With