I would like to know if @JsonTypeInfo
annotation can be used for interfaces. I have set of classes which should be serialized and deserialized.
Here is what I'm trying to do. I have two implementation classes Sub1
, Sub2
implementing MyInt
. Some of the model classes have the interface reference for the implementation types. I would like to deserialize the objects based on polymorphism
@JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.WRAPPER_OBJECT) @JsonSubTypes({ @Type(name="sub1", value=Sub1.class), @Type(name="sub2", value=Sub2.class)}) public interface MyInt{ } @JsonTypeName("sub1") public Sub1 implements MyInt{ } @JsonTypeName("sub2") public Sub2 implements MyInt{ }
I get the following JsonMappingException
:
Unexpected token (END_OBJECT), expected FIELD_NAME: need JSON String that contains type id
Jackson Annotations - @JacksonInject @JacksonInject is used when a property value is to be injected instead of being parsed from Json input. In the example below, we are inserting a value into object instead of parsing from the Json.
@JsonTypeInfo is used to indicate details of type information which is to be included in serialization and de-serialization.
The @JsonTypeId annotation is used to indicate that the annotated property should be serialized as the type id when including polymorphic type information, rather than as a regular property.
@JsonCreator is used to fine tune the constructor or factory method used in deserialization. We'll be using @JsonProperty as well to achieve the same. In the example below, we are matching an json with different format to our class by defining the required property names.
@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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With