Best way to deserialize json objects based in property value

Viewed 441

I want to convert JSON string into objects and I'm trying to find the best way to do that since those objects are really similar and the only change is the "data" field between them:

{
  "event_type": "REGISTER",
  "day": "2021-01-01",
  "data": {
    "name": "Kyore",
    "age": 10
  }
}

{
  "event_type": "DELETE",
  "day": "2021-01-01",
  "data": {
    "id": "1234-1234-1234",
    "reason": "user requested"
  }
}

Those events come from a SQS Listener as a JSON string and I'm trying to find the best way to handle them with Kotlin, but I'm not sure how to pick which class will be the one to be converted in my listener:

abstract class Event {
    abstract val event_type: String
    abstract val day: String
    abstract val data: EventData

    abstract class EventData
}

class RegisterEvent(
    override val eventType: String,
    override val day: String,
    override val data: RegisterData
) : Event() {

    data class RegisterData(
        val name: String,
        val age: Int
    ) : Event.EventData()
}

class DeleteEvent(
    override val eventType: String,
    override val day: String,
    override val data: DeleteData
) : Event() {

    data class RegisterData(
        val id: String,
        val reason: String
    ) : Event.EventData()
}

What is the best way to convert the message string in the correct event?

1 Answers

After a while reading about Polymorphic Deserialization, I found a solution to that using Kotlin and Jackson, which basically we need to use the @JsonTypeInfo and @JsonSubTypes from jackson's annotations and tell it which property will be checked to deserialize and which Class should be used when it match, using the OP example:

data class Event(
   val event_type: String,
   val day: String,
   val data: EventData
) {

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "event_type", include = JsonTypeInfo.As.EXTERNAL_PROPERTY)
    @JsonSubTypes(value = [
        JsonSubTypes.Type(RegisterData::class, name = "REGISTER"),
        JsonSubTypes.Type(DeleteData::class, name = "DELETE")
    ])
   abstract class EventData
}

data class RegisterData(
    val name: String,
    val age: Int
) : Event.EventData()

data class DeleteData(
    val id: String,
    val reason: String
) : Event.EventData()

So when we convert the JSON string into the Event object, the data property will be mapped with one of the RegisterData and DeleteData classes.

Related