Polymorphism in jackson annotations: @JsonTypeInfo usage
@JsonSubTypes.Type
must have a value and a name like this,
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.WRAPPER_OBJECT, property="type")
@JsonSubTypes({
@JsonSubTypes.Type(value=Dog.class, name="dog"),
@JsonSubTypes.Type(value=Cat.class, name="cat")
})
In the subclass, use @JsonTypeName("dog")
to say the name.
The values dog
and cat
will be set in the property named type
.
Yes it can be used both for abstract classes and interfaces.
Consider following code example
Suppose we have an enum , interface and classes
enum VehicleType {
CAR,
PLANE
}
interface Vehicle {
VehicleType getVehicleType();
String getName();
}
@NoArgsConstructor
@Getter
@Setter
class Car implements Vehicle {
private boolean sunRoof;
private String name;
@Override
public VehicleType getVehicleType() {
return VehicleType.Car;
}
}
@NoArgsConstructor
@Getter
@Setter
class Plane implements Vehicle {
private double wingspan;
private String name;
@Override
public VehicleType getVehicleType() {
return VehicleType.Plane;
}
}
If we try to deserialize this json into List<Vehicle>
[
{"sunRoof":false,"name":"Ferrari","vehicleType":"CAR"},
{"wingspan":19.25,"name":"Boeing 750","vehicleType":"PLANE"}
]
then we will get error
abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
To solve this just add following JsonSubTypes
and JsonTypeInfo
annotations to the interface, as shown below
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
property = "vehicleType")
@JsonSubTypes({
@JsonSubTypes.Type(value = Car.class, name = "CAR"),
@JsonSubTypes.Type(value = Plane.class, name = "PLANE")
})
interface Vehicle {
VehicleType getVehicleType();
String getName();
}
With this the deserialization will work with interface and you will get a List<Vehicle>
back
You can check out the code here - https://github.com/chatterjeesunit/java-playground/blob/master/src/main/java/com/play/util/jackson/PolymorphicDeserialization.java