In this blog post we'll deal with one particularly nasty topic: circular references. You might have heard about circular references in your computer science or math class on graphs. In a more practical explanation: it deals with the case when objects have a nested property to a different object, which then references back to the original one. This scenario will cause Gson to crash your app. If you want to know how you can deal with this, keep reading!
Of course, this is not the only post in our Gson series. If you're interested in the other topics, check out our series outline:
Gson Series Overview
- Mapping of Enums
- Mapping of Circular References
- Generics
- Custom Serialization for Simplification (Part 1)
- Changing the Default Serialization with Custom Serialization (Part 2)
- Custom Deserialization Basics
- Custom Instance Creator
- Customizing (De)Serialization via @JsonAdapter
- Custom Deserialization for Calculated Fields
- On-The-Fly-Parsing With Streams
- ProGuard Configuration
Gson and the StackOverflowError
The alternative title of this blog post could have been: Why does Gson cause a java.lang.StackOverflowError
?
Just think of it from a serialization perspective: as you've read in the nested objects blog post, Gson needs to create a new JSON subelement for every referenced object. If object A
references to object B
, Gson will need to create a subelement in A
for B
. If B
references back to A
, we're stuck in an infinite loop and will keep creating new subelements, which create new subelements, and so on. Eventually, this will trigger the StackOverflowError
.
Let's visualize this scenario with some actual code:
public class UserCircular {
String name;
String email;
int age;
boolean isDeveloper;
// references to child & parent node
UserCircular child;
UserCircular parent;
}
Imagine your app builds a family tree. Then every family member might be wrapped in the UserCircular
class you can see above. Alright, the child
and parent
property should probably be a list, but that doesn't change anything.
From a programming perspective, this is a total valid implementation. Unfortunately, you won't be able to serialize it. There's no JSON equivalent which holds the same data format, since we'll be stuck in that infinite loop.
The solution is simple: you'll have to exclude one graph reference from the serialization. You can read here more about various options to achieve this. A simple way would be to add transient
to the parent
property:
public class UserCircular {
String name;
String email;
int age;
boolean isDeveloper;
// references to child & parent node
UserCircular child;
transient UserCircular parent;
}
Internally nothing changes for your app. Nevertheless, parent
would not be serialized anymore and you're out of that infinite loop:
{
"age": 26,
"childUser": {
"age": 26,
"email": "norman@futurestud.io",
"isDeveloper": true,
"name": "Norman"
},
"email": "norman@futurestud.io",
"isDeveloper": true,
"name": "Norman"
}
All the necessary data would still be serialized. The server would need to create the back-reference again, if that's required.
Outlook
In this blog post you've learned when Gson can run into an infinite loop and throws a StackOverflowError
at you. You can solve this problem by excluding one graph pointer from the serialization.
If you've feedback or a question, let us know in the comments or on twitter @futurestud_io.
Make it rock & enjoy coding!