Java Jackson @JsonIdentityInfo Example

1. Introduction

Handling cyclic object references in Java can be quite challenging when it comes to serialization. Infinite loops and StackOverflowErrors are common pitfalls. Jackson provides @JsonIdentityInfo, an annotation that helps in resolving these cyclic dependencies, ensuring objects are serialized only once and then referenced using an identifier for subsequent occurrences.

2. Example Steps

1. Define two classes, Person and Company, having a bidirectional relationship.

2. Annotate the Person class with @JsonIdentityInfo to provide an identifier for each serialized object instance.

3. Serialize a Company instance with multiple Person references.

4. Print the serialized JSON string.

3. Java Jackson @JsonIdentityInfo Example

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;

public class JsonIdentityInfoExample {

    @JsonIdentityInfo(
      generator = ObjectIdGenerators.PropertyGenerator.class,
      property = "id")
    public static class Person {
        public int id;
        public String name;
        public Company worksAt;

        public Person(int id, String name) {
            this.id = id;
            this.name = name;
        }
    }

    public static class Company {
        public String companyName;
        public Person employee;

        public Company(String companyName, Person employee) {
            this.companyName = companyName;
            this.employee = employee;
        }
    }

    public static void main(String[] args) throws JsonProcessingException {
        Person person = new Person(1, "John Doe");
        Company company = new Company("TechCorp", person);
        person.worksAt = company; // Establishing bidirectional relationship

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

        System.out.println(result);
    }
}

Output:

{"companyName":"TechCorp","employee":{"id":1,"name":"John Doe","worksAt":{"companyName":"TechCorp","employee":1}}}

4. Step By Step Explanation

When we have objects with bidirectional relationships, as seen with Person and Company, serialization can become problematic. Without care, serializing the Company would serialize its employee, which would in turn serialize its worksAt field, leading us back to the Company again and creating an infinite loop.

The @JsonIdentityInfo annotation prevents this. It marks an object the first time it's encountered during serialization by an identifier (in this case, the id property of Person). On subsequent encounters with the same object, instead of serializing the object all over again, Jackson just uses this identifier to reference the already-serialized instance.

Thus, in our output, the employee within the worksAt field of Person is represented by the integer 1, which is the id of John Doe. This is much cleaner, more efficient, and prevents potential infinite loops.


Comments