I have a Kotlin sealed class - Pet
and two subclasses - Dog
and Cat
. My application requires to transfer a collection of pets serialized in JSON. In order to differentiate subclasses I use Jackson @JsonTypeInfo
and @JsonSubTypes
annotations. The listing below:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes(
JsonSubTypes.Type(value = Dog::class, name = "dog"),
JsonSubTypes.Type(value = Cat::class, name = "cat")
)
sealed class Pet { abstract val name: String }
data class Dog(override val name: String): Pet()
data class Cat(override val name: String): Pet()
Single instances are serialized and deserialized properly:
@Test
fun `serialize dog`() {
val dog = Dog("Kevin")
val dogJson = objectMapper.writeValueAsString(dog)
JsonAssert.assertEquals(dogJson, """{"type":"dog","name":"Kevin"}""")
val newDog = objectMapper.readValue<Dog>(dogJson)
}
The problem comes up when a collection of pets is being serialized and deserialized:
@Test
fun `serialize dog and cat`() {
val pets: Set<Pet> = setOf(Dog("Kevin"), Cat("Marta"))
val petsJson = objectMapper.writeValueAsString(pets)
JsonAssert.assertEquals(petsJson, """[{"name":"Kevin"},{"name":"Marta"}]""")
val newPets = objectMapper.readValue<Set<Pet>>(petsJson)
}
Jackson swallows the type property during serialization and because of that objectMapper
is not able to readValue
:
com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Missing type id when trying to resolve subtype of [simple type, class s3.moria.workflows.common.model.Pet]: missing type id property 'type'
at [Source: (String)"[{"name":"Kevin"},{"name":"Marta"}]"; line: 1, column: 17] (through reference chain: java.util.HashSet[0])
Any ideas how tackle this problem? Or workarounds?
Jackson version: 2.9.0