I'm using the @JsonTypeInfo annotation of jackson in order to define a way to deserialize a property that is defined by an Interface.
I'm using include = JsonTypeInfo.As.EXTERNAL_PROPERTY property in order to set the property included in the outer object.
I also using defaultImpl to set the failsafe class if the property is not set.
I would like that if the id is missing, the failback class is used to deserialize the parameters property like in the unit test:
public class DeserializationTest {
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
public static class OuterClass {
public String id;
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
defaultImpl = InnerImpl.class,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "id"
)
@JsonSubTypes(
@JsonSubTypes.Type(value = InnerImpl2.class, name = "non_default")
)
public Parameters parameters;
}
public interface Parameters {
}
public static class InnerImpl implements Parameters {
public String property;
}
public static class InnerImpl2 implements Parameters {
public String property2;
}
@Test
public void testDeserializationDefault() throws IOException {
OuterClass o = OBJECT_MAPPER.readValue(
"{\"parameters\": {\"property\":\"test\"}, \"id\":\"default\"}", OuterClass.class
);
Assert.assertEquals(InnerImpl.class, o.parameters.getClass());
Assert.assertEquals("test", ((InnerImpl) o.parameters).property);
}
@Test
public void testDeserializationDefaultWithoutId() throws IOException {
OuterClass o = OBJECT_MAPPER.readValue(
"{\"parameters\": {\"property\":\"test\"}}", OuterClass.class
);
Assert.assertEquals(InnerImpl.class, o.parameters.getClass());
Assert.assertEquals("test", ((InnerImpl) o.parameters).property);
}
@Test
public void testDeserializationNonDefault() throws IOException {
OuterClass o = OBJECT_MAPPER.readValue(
"{\"parameters\": {\"property2\":\"test\"}, \"id\":\"non_default\"}", OuterClass.class
);
Assert.assertEquals(InnerImpl2.class, o.parameters.getClass());
Assert.assertEquals("test", ((InnerImpl2) o.parameters).property2);
}
}
But I got this error on the second test: testDeserializationDefaultWithoutId
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `com.ovh.serving.hub.SerializationTest$InnerImpl` out of VALUE_NULL token
at [Source: (String)"{"parameters": {"storagePath":"storagePathTest"}}"; line: 1, column: 49]
EDIT: Add use case with specific id
EDIT2: It's works with JsonTypeInfo.As.PROPERTY if the id is in the inner class
You are telling Jackson to include an external property named id, that's why it requires the id property.
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "id",
defaultImpl = InnerImpl.class
)
Remove include and property from @JsonTypeInfo and it will work. Your annotation should be:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
defaultImpl = InnerImpl.class
)
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