import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.databind.annotation.NoClass
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
sealed class Entity
data class Bacteria(val speciesName: String): Entity()
data class Disease(val diseaseId: Long): Entity()
enum class EntityType {
MY_Bacteria,
MY_Disease
}
data class MyRequestBody(
val entityType: EntityType,
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "entityType",
defaultImpl = NoClass::class,
visible = true
)
@JsonSubTypes(
JsonSubTypes.Type(value = Disease::class, name = "MY_Disease"),
JsonSubTypes.Type(value = Bacteria::class, name = "MY_Bacteria")
)
val entity: Entity? = null
)
fun main() {
val jsonString = """{
| "entityType": "MY_Bacteria"
|}""".trimMargin()
val reader = jacksonObjectMapper()
val deserialized = reader.readValue<MyRequestBody>(jsonString)
println(deserialized)
}
results in
Exception in thread "main" com.fasterxml.jackson.databind.exc.MismatchedInputException: Missing property 'entity' for external type id 'entityType'
at [Source: (String)"{
"entityType": "MY_Bacteria"
}"; line: 3, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1356)
at com.fasterxml.jackson.databind.deser.impl.ExternalTypeHandler.complete(ExternalTypeHandler.java:281)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeUsingPropertyBasedWithExternalTypeId(BeanDeserializer.java:1001)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeWithExternalTypeId(BeanDeserializer.java:853)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:324)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4013)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3023)
at MainKt.main(Main.kt:40)
at MainKt.main(Main.kt)
However, if we change it to use JsonTypeInfo.As.PROPERTY, it works for the missing field
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.databind.annotation.NoClass
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
sealed class Entity(val entityType: EntityType)
data class Bacteria(val speciesName: String): Entity(EntityType.MY_Bacteria)
data class Disease(val diseaseId: Long): Entity(EntityType.MY_Disease)
enum class EntityType {
MY_Bacteria,
MY_Disease
}
data class MyRequestBody(
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "entityType",
defaultImpl = NoClass::class,
visible = true
)
@JsonSubTypes(
JsonSubTypes.Type(value = Disease::class, name = "MY_Disease"),
JsonSubTypes.Type(value = Bacteria::class, name = "MY_Bacteria")
)
val entity: Entity? = null
)
fun main() {
val jsonString = "{}"
val reader = jacksonObjectMapper()
val deserialized = reader.readValue<MyRequestBody>(jsonString)
println(deserialized)
}
results in
However, if we change it to use
JsonTypeInfo.As.PROPERTY
, it works for the missing fieldIt successfully prints
MyRequestBody(entity=null)