Reputation: 2605
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
Upvotes: 4
Views: 1142
Reputation: 1938
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
)
Upvotes: 1