JsonContentPolymorphicSerializer

abstract class JsonContentPolymorphicSerializer<T : Any>(baseClass: KClass<T>) : KSerializer<T> (source)

Base class for custom serializers that allows selecting polymorphic serializer without a dedicated class discriminator, on a content basis.

Usually, polymorphic serialization (represented by PolymorphicSerializer and SealedClassSerializer) requires a dedicated "type" property in the JSON to determine actual serializer that is used to deserialize Kotlin class.

However, sometimes (e.g. when interacting with external API) type property is not present in the input and it is expected to guess the actual type by the shape of JSON, for example by the presence of specific key. JsonContentPolymorphicSerializer provides a skeleton implementation for such strategy. Please note that since JSON content is represented by JsonElement class and could be read only with JsonDecoder decoder, this class works only with Json format.

Deserialization happens in two stages: first, a value from the input JSON is read to as a JsonElement. Second, selectDeserializer function is called to determine which serializer should be used. The returned serializer is used to deserialize JsonElement back to Kotlin object.

It is possible to serialize values this serializer. In that case, class discriminator property won't be added to JSON stream, i.e., deserializing a class from the string and serializing it back yields the original string. However, to determine a serializer, a standard polymorphic mechanism represented by SerializersModule is used. For convenience, serialize method can lookup default serializer, but it is recommended to follow standard procedure with registering.

Usage example:

interface Payment {
val amount: String
}

@Serializable
data class SuccessfulPayment(override val amount: String, val date: String) : Payment

@Serializable
data class RefundedPayment(override val amount: String, val date: String, val reason: String) : Payment

object PaymentSerializer : JsonContentPolymorphicSerializer<Payment>(Payment::class) {
override fun selectDeserializer(content: JsonElement) = when {
"reason" in content.jsonObject -> RefundedPayment.serializer()
else -> SuccessfulPayment.serializer()
}
}

// Now both statements will yield different subclasses of Payment:

Json.decodeFromString(PaymentSerializer, """{"amount":"1.0","date":"03.02.2020"}""")
Json.decodeFromString(PaymentSerializer, """{"amount":"2.0","date":"03.02.2020","reason":"complaint"}""")

Parameters

T

A root type for all classes that could be possibly encountered during serialization and deserialization. Must be non-final class or interface.

baseClass

A class token for T.

Constructors

Link copied to clipboard
constructor(baseClass: KClass<T>)

Properties

Link copied to clipboard
open override val descriptor: SerialDescriptor

A descriptor for this set of content-based serializers. By default, it uses the name composed of baseClass simple name, kind is set to PolymorphicKind.SEALED and contains 0 elements.

Functions

Link copied to clipboard
override fun deserialize(decoder: Decoder): T
Link copied to clipboard
override fun serialize(encoder: Encoder, value: T)