JSON serialization and deserialization: Circular References

In recent times, I did a lot practise of micro-service with spring boot. And handled a lot of JSON(Jackson) related serialization and deserialization issues. In this post, I will share some tricky how to “fix” Circular References.

Note: What I want to do are:

  1. I can serialize object to JSON string
  2. I can deserialize the JSON string to the same object(at least all important info retains)

Circular References

Let’s see a quick demo first: (Book has its Author, while Author keeps a list of his/her Books)

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Book {
private String name;
private Author author;
// getter & setter
}
public class Author {
private String name;
private List<Book> books;
// getter & setter
}

Now, we can have a serialization sample as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) throws IOException {
Book book = new Book();
book.setName("Book");
Author author = new Author();
author.setName("Author");
List<Book> books = new ArrayList<Book>();
books.add(book);
author.setBooks(books);
book.setAuthor(author);
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writeValueAsString(book));
System.out.println(mapper.writeValueAsString(author));
}

Then it will throw this exception:

Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: ...

JSON is pretty to hard to demonstrate the data with Circular References

Solution:

Thx to Jackson, with @JsonIdentityInfo, we can easy fix this issue. After I add @JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="@id") to both class, then I can have the JSON string as:

1
{"@id":1,"name":"Book","author":{"@id":2,"name":"Author","books":[1]}}

1
{"@id":1,"name":"Author","books":[{"@id":2,"name":"Book","author":1}]}

However, I am not sure whether this JSON string can be deserialized by other libraries(e.g. GSON), or other languages, my guess is NOT.

Note: Think twice before using it!