Java Jackson @JsonSubTypes Example

1. Introduction

When working with polymorphic types in Java, the Jackson library offers a suite of annotations to handle the serialization and deserialization of these types effectively. One of the key annotations in this suite is @JsonSubTypes. This annotation is used to indicate subtypes of annotated types, so Jackson can correctly determine which class to use when deserializing JSON data into Java objects.

2. Example Steps

1. Create an abstract base class Vehicle and two derived classes Car and Bike.

2. Apply the @JsonSubTypes annotation to the base class to indicate its subtypes.

3. Serialize and deserialize a Vehicle object to showcase the functionality of the annotation.

3. Java Jackson @JsonSubTypes Example

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.databind.ObjectMapper;

public class JacksonJsonSubTypesExample {

    public static void main(String[] args) throws Exception {
        // Create a Car object
        Vehicle vehicle = new Car("Red", 4);

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

        // Serialize the Car object to JSON
        String jsonString = mapper.writeValueAsString(vehicle);

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

        // Deserialize the JSON back to a Vehicle object
        Vehicle deserializedVehicle = mapper.readValue(jsonString, Vehicle.class);

        // Print the details of the deserialized vehicle
        System.out.println(deserializedVehicle.toString());
    }
}

@JsonTypeInfo(
    use = JsonTypeInfo.Id.NAME,
    include = JsonTypeInfo.As.PROPERTY,
    property = "vehicleType"
)
@JsonSubTypes({
    @JsonSubTypes.Type(value = Car.class, name = "car"),
    @JsonSubTypes.Type(value = Bike.class, name = "bike")
})
abstract class Vehicle {
    abstract String toString();
}

class Car extends Vehicle {
    private String color;
    private int doors;

    public Car(String color, int doors) {
        this.color = color;
        this.doors = doors;
    }

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

class Bike extends Vehicle {
    private String model;

    public Bike(String model) {
        this.model = model;
    }

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

Output:

{"vehicleType":"car","color":"Red","doors":4}
Car [color=Red, doors=4]

4. Step By Step Explanation

The @JsonSubTypes annotation is used to define the subtypes of a given base type. In our example, Vehicle is the base type, and Car and Bike are its subtypes. The name attribute in the @JsonSubTypes.Type annotation is used to specify the value of the type identifier in the JSON data. This type identifier is crucial as it helps Jackson determine which Java class to map the JSON data to during the deserialization process.

When we serialize our Car object, Jackson includes a vehicleType property in the JSON (as defined by the property attribute in the @JsonTypeInfo annotation). This property's value (in this case, "car") tells Jackson which subtype this JSON should be deserialized to.

In our example, after deserializing the JSON, Jackson correctly identifies and instantiates a Car object because of the "car" value in the vehicleType property.


Comments