jackson-module-model-versioning
jackson-module-model-versioning copied to clipboard
Migration from JsonSubTypes with empty super type fails
Given the types MySuperDto
, MySubDto
, MyEmptySubDto
, see below.
For version 1 the super type added a the field superField
, but was empty at version 0.
Reading this Json, at version 0, with a reader for the super type MySuperDto
{
"type" : "MyEmptySubDto"
}
will fail throwing
com.fasterxml.jackson.databind.JsonMappingException: value must be a JSON object
at [Source: (String)"{
"type" : "MyEmptySubDto"}"; line: 2, column: 27]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:274)
at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:1844)
at com.github.jonpeterson.jackson.module.versioning.VersionedModelDeserializer.deserialize(VersionedModelDeserializer.java:75)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer._deserializeTypedForId(AsPropertyTypeDeserializer.java:130)
at com.fasterxml.jackson.databind.jsontype.impl.AsPropertyTypeDeserializer.deserializeTypedFromObject(AsPropertyTypeDeserializer.java:97)
at com.fasterxml.jackson.databind.deser.AbstractDeserializer.deserializeWithType(AbstractDeserializer.java:254)
at com.fasterxml.jackson.databind.deser.impl.TypeWrappedDeserializer.deserialize(TypeWrappedDeserializer.java:68)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4218)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3214)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3182)
Details on sub types
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "type"
)
@JsonSubTypes({
@JsonSubTypes.Type(value = MySubDto.class, name = "MySubDto"),
@JsonSubTypes.Type(value = MyEmptySubDto.class, name = "MyEmptySubDto")
})
@JsonVersionedModel(
currentVersion = "1",
defaultDeserializeToVersion = "0",
toCurrentConverterClass = ToCurrentMySuperDto.class)
static abstract class MySuperDto {
@JsonProperty(required = true)
public String superField;
@JsonCreator
public MySuperDto(
@JsonProperty(required = true, value = "superField") String superField
) {
this.superField = superField;
}
}
static class MySubDto extends MySuperDto {
@JsonProperty
String subField;
@JsonCreator
public MySubDto(
@JsonProperty(required = true, value = "superField") String superField,
@JsonProperty(required = true, value = "subField") String subField
) {
super(superField);
this.subField = subField;
}
}
static class MyEmptySubDto extends MySuperDto {
@JsonCreator
public MyEmptySubDto(
@JsonProperty(required = true, value = "superField") String superField
) {
super(superField);
}
}
A fix might be to add something like
if (jsonNode.isNull()) {
jsonNode = (JsonNode) parser.getCodec().createObjectNode();
}
before the deserializer throws.
@jonpeterson If you think that's a feasible approach, I can give it a try.