0

I'm having a really difficult time working this out. I have a polymorphic JSON structure that I want to parse and flatten. Basically this:

{
  "objectType": "type",
  "data": {...}
}

And the data object changes depending on type. What I would like to achieve is have a possibility to parse this json directly into a structure which only contains fields in data object. Preferably it should work on polymorphic principle like this:


@Serializable
@JsonClassDiscriminator("type")
abstract class Thing(val type: String)

@Serializable
@SerialName("image")
data class Image(val url: String, val width: Int, val height: Int): Thing("image")

val string = """
{
  "type": "image",
  "data": {
    "url": "..",
    "width": 140,
    "height": 250
  }
}
"""

println(Json.decodeFromString<Image>(string)))

I know it can be easily done by unwrapping manually but the api I'm interacting with has every single type (hundreds of them) inheriting from that Thing type and unwrapping it manually each time and writing separate implementation for all of them seems tedious and I would rather spent a week trying to figure out a generic solution for all.

The easiest way would be to implement a custom serializer for Thing like in this article but it must be terribly outdated cause I couldn't get that approach to work.

Ernest Zamelczyk
  • 2,562
  • 2
  • 18
  • 32
  • If by "unwrapping manually" you mean depending on `objectType` deserializing `data` differently, that _is_ polymorphic deserialization. No real way around it. You can store the type discriminator (seemingly `objectType` in the JSON output in the API you are using) elsewhere, but it's necessary information. – Steven Jeuris Feb 28 '22 at 18:02
  • At a glance, you can probably create a `Thing` class with a `TData` field. For all "things" you then create a simple oneliner extending class, and you create serializable types for `TData`. You should then register all of these classes for polymorphic serialization, or, make the base `Thing` sealed. – Steven Jeuris Feb 28 '22 at 18:04
  • 1
    Yeah I know. That's what I'm doing right now. Each class just extends from `Thing` and the actual data is stored inside. So each class is still contained in an envelope and there is no other way around it. Bummer. I thought I could do something like an envelope unwrapper converter in retrofit. – Ernest Zamelczyk Mar 02 '22 at 10:23
  • Default poly serialization adds a `type` field to the object itself. Not in a wrapper. You could avoid the need for the `Thing` wrapper by writing a custom JSON-specific serializer which redirects to a poly serializer for your `data` type and transforms the JSON prior to deserializing and after serialization. – Steven Jeuris Mar 03 '22 at 07:57

0 Answers0