Java Jackson @JsonTypeName Example

1. Introduction

Jackson provides a rich set of annotations to control the serialization and deserialization of Java objects. When working with polymorphic types, we need a way to indicate the actual type of the serialized object. The @JsonTypeName annotation allows us to specify the name that will be used as the type identifier for the class when serialized and deserialized.

2. Example Steps

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

2. Apply the @JsonTypeName annotation to the derived classes to specify their type names.

3. Serialize and deserialize an Animal object to showcase the functionality of the annotation.

3. Java Jackson @JsonTypeName 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;

public class JacksonJsonTypeNameExample {

    public static void main(String[] args) throws Exception {
        // Create a Dog object
        Animal animal = new Dog("Bulldog");

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

        // Serialize the Dog object to JSON
        String jsonString = mapper.writeValueAsString(animal);

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

        // Deserialize the JSON back to an Animal object
        Animal deserializedAnimal = mapper.readValue(jsonString, Animal.class);

        // Print the details of the deserialized animal
        System.out.println(deserializedAnimal.toString());
    }
}

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "animalType"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Dog.class),
    @JsonSubTypes.Type(value = Cat.class)
})
abstract class Animal {
    abstract String toString();
}

@JsonTypeName("doggy")
class Dog extends Animal {
    private String breed;

    public Dog(String breed) {
        this.breed = breed;
    }

    @Override
    public String toString() {
        return "Dog [breed=" + breed + "]";
    }
}

@JsonTypeName("kitty")
class Cat extends Animal {
    private String color;

    public Cat(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Cat [color=" + color + "]";
    }
}

Output:

{"animalType":"doggy","breed":"Bulldog"}
Dog [breed=Bulldog]

4. Step By Step Explanation

The @JsonTypeName annotation is used in combination with the @JsonTypeInfo and @JsonSubTypes annotations to handle polymorphism in Jackson. In our example, the abstract Animal class is the base type, and the Dog and Cat classes are its subtypes.

Using @JsonTypeName, we specify that the Dog class should have a type name of "doggy" and the Cat class should have a type name of "kitty". These type names are then used as the type identifiers in the serialized JSON data.

In the provided example, when we serialize our Dog object, Jackson includes an animalType property in the JSON (as defined by the property attribute in the @JsonTypeInfo annotation). This property's value ("doggy") matches the value provided in the @JsonTypeName annotation for the Dog class. When deserializing, Jackson uses this type of identifier to instantiate the correct subtype.

The @JsonTypeName annotation helps ensure that the correct subtype is chosen during deserialization by providing an explicit type name for each class.


Comments