0
votes

Let's assume I have following json objects :

{
    "type": "video",
    "...": "..."
}
{
    "type": "image",
    "...": "..."
}

They both represent media object. Kotlin sealed model looks like :

sealed class Media {
    ...
}

@Serializable
@SerialName("video")
data class Video(...) : Media()

@Serializable
@SerialName("image")
data class Image(...) : Media()

According KoltinX doc, I used a wrapper for polymorphic serialization :

@Serializable
private data class MediaWrapper(@Polymorphic val media: Media) {
    companion object {
        val jsonSerializer = Json(
            context = SerializersModule {
                polymorphic<Media> {
                    Video::class with Video.serializer()
                    Image::class with Image.serializer()
                }
            }
        )

        fun fromJson(json: String) = jsonSerializer.parse(serializer(), json)
    }
}

The goal is to deserialize a Media json using my wrapper, but problem is I need to change my Media json into a MediaWrapper json. The most convenient solution I found is to add {\"media\":\" & \"} on each side of my Media json:

sealed class Media {
    companion object {
        fun fromJson(mediaJson: String): Media {
            val mediaWrapperJson = "{\"media\":$mediaJson}"
            val mediaWrapper = MediaWrapper.fromJson(mediaWrapperJson)
            return mediaWrapper.media
        }
    }
}

This is a trick, if there is a more convenient way to deserialize polymorphics, please let me know!

1
how I should apply this to my dataclass containing the field? With @SerializableName then write custom deserializer? Please extend - nutella_eater

1 Answers

3
votes

While the kotlinx serialization docs use a wrapper in many of its polymorphic examples, it does not say that this pattern is mandatory.

From the docs:

Pro tip: to use Message without a wrapper, you can pass PolymorphicSerializer(Message::class) to parse/stringify.

In your case you could do:

sealed class Media {
    companion object {
        val jsonSerializer = Json(
            context = SerializersModule {
                polymorphic<Media> {
                    Video::class with Video.serializer()
                    Image::class with Image.serializer()
                }
            }
        )

        fun fromJson(mediaJson: String): Media {
           return jsonSerializer.parse(PolymorphicSerializer(Media::class), mediaJson) as Media
        }
    }
}