I’m just trying to achieve to deserialize a nested polymorphed data class but i’m not able to do so. The previous questions and answers didn’t help me much for achieving this task that looks simple. I still get this error no matter I add constructor, add more annotation etc. Very confused.
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `Dog` (no Creators, like default constructor, exist): abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes(
JsonSubTypes.Type(value = Dog::class, name = "dog"),
)
sealed class Animal(val name: String)
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type"
)
@JsonSubTypes(
JsonSubTypes.Type(value = Labrador::class, name = "labrador")
)
sealed class Dog(name: String, val breed: String) : Animal(name)
class Labrador(name: String, val color: String) : Dog(name, "Labrador")
fun main() {
val json = """
{
"type": "dog",
"name": "Buddy",
"breed": "Labrador",
"color": "golden"
}
"""
val objectMapper = jacksonObjectMapper()
val animal: Animal = objectMapper.readValue(json)
println(animal.javaClass) // class com.example.Dog
println(animal.name) // Buddy
println((animal as Dog).breed) // Labrador
println((animal as? Labrador)?.color) // golden
}
2
Answers
I’m not a Jackson expert, but I think when you specify
"type": "dog"
Jackson tries to create an instance of classDog
, which is asealed class
. Sealed classes are always abstract, hence the exception. If you makeDog
anopen
class instead ofsealed
(and add@JsonIgnoreProperties(ignoreUnknown = true)
to ignore unknown property"color": "golden"
), your code will should print:If you want to get an instance of
Labrador
you have to change type:"type": "labrador"
, because type can not be bothdog
andlabrador
. Now it should print: