Java Jackson @JsonTypeInfo Example

1. Introduction

In object-oriented programming, polymorphism enables us to treat derived classes as their base type. However, when it comes to JSON serialization/deserialization, preserving this polymorphic nature isn't straightforward. Jackson's @JsonTypeInfo annotation is a powerful tool to include type information in the JSON, which helps in preserving the object's actual class information. This is crucial when deserializing polymorphic types.

2. Example Steps

1. Create an abstract base class Animal and two derived classes Cat and Dog.

2. Apply the @JsonTypeInfo annotation on the base class to include type metadata during serialization.

3. Serialize and deserialize a list of Animal objects to demonstrate the utility of the annotation.

3. Java Jackson @JsonTypeInfo Example

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Arrays;
import java.util.List;

public class JacksonJsonTypeInfoExample {

    public static void main(String[] args) throws Exception {
        // Create a list of Animal objects
        List<Animal> animals = Arrays.asList(new Dog("Barky"), new Cat("Whiskers"));

        // Initialize ObjectMapper
        ObjectMapper mapper = new ObjectMapper();

        // Serialize the list to JSON
        String jsonString = mapper.writeValueAsString(animals);

        // Print the serialized JSON
        System.out.println(jsonString);

        // Deserialize the JSON back to a list of Animal objects
        Animal[] deserializedAnimals = mapper.readValue(jsonString, Animal[].class);

        // Print the names of deserialized animals
        for (Animal animal : deserializedAnimals) {
            System.out.println(animal.getName());
        }
    }
}

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "type"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class, name = "dog"),
    @JsonSubTypes.Type(value = Cat.class, name = "cat")
})
abstract class Animal {
    private String name;

    // Constructor, getters, and setters
    public Animal(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

@JsonTypeName("dog")
class Dog extends Animal {
    public Dog(String name) {
        super(name);
    }
}

@JsonTypeName("cat")
class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }
}

Output:

[{"type":"dog","name":"Barky"},{"type":"cat","name":"Whiskers"}]
Barky
Whiskers

4. Step By Step Explanation

The @JsonTypeInfo annotation is applied to our abstract base class Animal. This instructs Jackson to include a property named "type" in the serialized JSON, which will store type metadata (either "dog" or "cat" in this example). This way, when Jackson serializes derived objects, it embeds the type information within the JSON, and when deserializing, Jackson can identify the exact class to instantiate.

The @JsonSubTypes annotation, used in tandem with @JsonTypeInfo, helps Jackson map the "type" values to their corresponding classes. The @JsonTypeName annotation in the derived classes (Dog and Cat) provides a name to use in the JSON representation.

So, when we serialize our list of Animal objects, Jackson includes the type information. During deserialization, Jackson uses this type of metadata to correctly instantiate Dog and Cat objects.


Comments