Java Jackson @JsonManagedReference Example

1. Introduction

In scenarios involving bidirectional relationships between entities, serializing such entities can lead to infinite recursion and consequently a StackOverflowError. Jackson provides two annotations, @JsonManagedReference and @JsonBackReference, to handle such situations. In this post, we'll focus on the @JsonManagedReference.

2. Example Steps

1. Create two classes, User and Post, representing a user and their posts respectively. There's a bidirectional relationship: a user can have multiple posts, and each post has a reference to its user.

2. Annotate the 'posts' field in the User class with @JsonManagedReference to indicate it's the forward part of the relationship.

3. Serialize a sample User object with associated Post objects to JSON.

4. Print the serialized JSON string.

3. Java Jackson @JsonManagedReference Example

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.util.List;

public class JsonManagedReferenceExample {

    public static class User {
        public int id;
        public String name;
        // Annotating the forward part of the relationship
        @JsonManagedReference
        public List<Post> posts;

        public User(int id, String name, List<Post> posts) {
            this.id = id;
            this.name = name;
            this.posts = posts;
        }
    }

    public static class Post {
        public int postId;
        public String content;
        public User user;

        public Post(int postId, String content, User user) {
            this.postId = postId;
            this.content = content;
            this.user = user;
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        User user = new User(1, "John", List.of(new Post(101, "Hello World", null)));
        user.posts.get(0).user = user;

        ObjectMapper mapper = new ObjectMapper();
        String result = mapper.writeValueAsString(user);

        System.out.println(result);
    }
}

Output:

{"id":1,"name":"John","posts":[{"postId":101,"content":"Hello World"}]}

4. Step By Step Explanation

@JsonManagedReference and its counterpart @JsonBackReference help in handling and resolving infinite recursion problems that can arise due to bidirectional relationships in entities.

In our example, a User can have multiple Post entities and each Post references back to its User. Without any special handling, serializing a User object would involve serializing its posts, and each post would then serialize its user, leading to an endless cycle.

By marking the 'posts' field in the User class with @JsonManagedReference, we indicate that this side of the relationship should be serialized, while the back-reference in the Post class (the 'user' field) won't be serialized, thus preventing the infinite loop.

The output JSON string correctly represents the User and their Post without redundant back-references.


Comments