I got the following classes:
@JsonIdentityInfo(
generator = ObjectIdGenerators.IntSequenceGenerator.class,
property = "oid"
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "clazz")
@JsonSubTypes({
@JsonSubTypes.Type(value = MySubEntity.class, name = "MySubEntity"),
})
public abstract class Entity {
...
}
public class MySubEntity extends Entity {
...
}
Now when I serialize that MySubEntity
wrapped in an Optional
then JSON does not contain the clazz
attribute containing the type ID. Bug? When I serialize to List<MySubEntity>
or just to MySubEntity
it works fine.
Setup: jackson-databind 2.9.4, jackson-datatype-jdk8 2.9.4, serialization is done in Spring Boot application providing a RESTful web service.
EDIT: Here is the Spring REST method that returns the Optional
:
@RequestMapping(method = RequestMethod.GET, value = "/{uuid}", produces = "application/json")
public Optional<MySubEntity> findByUuid(@PathVariable("uuid") String uuid) {
...
}
EDIT:
I made a SSCCE with a simple Spring REST controller and two tests. The first test is using ObjectMapper
directly which is successful in deserialization although the clazz
is missing. The second test calls the REST controller and fails with an error because clazz
is missing:
Error while extracting response for type [class com.example.demo.MySubEntity] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Missing type id when trying to resolve subtype of [simple type, class com.example.demo.MySubEntity]: missing type id property 'clazz'; nested exception is com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class com.example.demo.MySubEntity]: missing type id property 'clazz'
This, indeed, looks like a bug. There is one workaround that I can suggest for this case, is to use JsonTypeInfo.As.EXISTING_PROPERTY
and add field clazz
to your Entity
. There only one case with this approach is that the clazz
must be set in java code manually. However this is easy to overcome.
Here is the full code for suggested workaround:
@JsonIdentityInfo(
generator = ObjectIdGenerators.IntSequenceGenerator.class,
property = "oid"
)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXISTING_PROPERTY, //field must be present in the POJO
property = "clazz")
@JsonSubTypes({
@JsonSubTypes.Type(value = MySubEntity.class, name = "MySubEntity"),
})
public abstract class Entity {
@JsonProperty
private String uuid;
//Here we have to initialize this field manually.
//Here is the simple workaround to initialize in automatically
@JsonProperty
private String clazz = this.getClass().getSimpleName();
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
}