I'm trying to deserialize JSON into different sealed subclasses, the class mappings work, but the actual values are all null
Example1:
{
"eventName": "SUCCESS",
"productName": "BLAH"
}
Example2:
{
"eventName": "FAILURE",
"productName": "BLAH",
"error": "Something went wrong"
}
The base sealed class looks like this:
@ExperimentalSerializationApi
@Serializable(with = EventSerializer::class)
sealed class Event {
val eventName: String? = null
val productName: String? = null
}
I have three subclasses
@Serializable
class EventFailure : Event()
@Serializable
class EventSuccess : Event()
@Serializable
class EventInvalid : Event()
and this is the Serializer
@ExperimentalSerializationApi
@Serializer(forClass = Event::class)
object EventSerializer : JsonContentPolymorphicSerializer<Event>(Event::class) {
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<out Event> {
return element.jsonObject["eventName"]?.jsonPrimitive?.content?.let {
when (EventType.valueOf(it)) {
EventType.FAILURE -> EventFailure.serializer()
EventType.SUCCESS -> EventSuccess.serializer()
}
} ?: EventInvalid.serializer()
}
}
When I deserialize a JSON list, all the values end up null:
val events = JSON.decodeFromString<Array<Event>>(it.body())
events.forEach {
println(it)
println(it.productName)
}
com.blah.EventSuccess@2ca132ad
null
com.blah.EventFailure@1686f0b4
null
If I change Event from a sealed class to a normal class without the custom serializer, data correctly deserializes into the Even class filling in all the values.
Any suggestions on how to make the deserialization into EventSuccess / EventFailure work correctly?
I made a custom JSON class with custom classDiscriminator
companion object {
val JSON = Json {
prettyPrint = true
ignoreUnknownKeys = true
encodeDefaults = true
classDiscriminator = "eventName"
}
}
@Serializable
@SerialName("SUCCESS")
class EventSuccess : Event()
@Serializable
@SerialName("FAILURE")
class EventFailure : Event()
and I removed the custom serializer
//@Serializable(with = EventSerializer::class)
@Serializable
sealed class Event {
and it's working correctly now.
I'm keeping the question open to see if there are perhaps ways of fixing the custom serializer implementation.