https://kotlinlang.org logo
#serialization
Title
# serialization
f

franztesca

10/05/2023, 9:31 PM
I'm dealing with an existing typescript definition that makes use of union type. I want to deserialize the Json of those types to ad-hoc data classes. I do that using sealed classes for union types. However, because the sealed class requires an additional wrapping data class, when serializing or deserializing the values I'm also getting the additional encoding of the wrapping class. Is there a way to avoid it? Practical example:
Copy code
// type RemoteMessage = string | ComplexClass
// valid RemoteMessages:
// 'hello'
// { blahBlah: 'hello' }
@Serializable
sealed class RemoteMessage {
    @Serializable
    data class StringType(val value: String): RemoteMessage()
    @Serializable
    data class ComplexType(val value: ComplexClass): RemoteMessage()

    object Serializer: JsonContentPolymorphicSerializer<RemoteMessage>(RemoteMessage::class) {
        override fun selectDeserializer(element: JsonElement): KSerializer<out RemoteMessage> {
            return when (element) {
                is JsonPrimitive -> StringType.serializer()
                is JsonObject -> ComplexType.serializer()
                else -> error("Unsupported type: ${element::class}")
            }
        }
    }
}

@Serializable
data class ComplexClass(
    val blahBlah: String,
    // ...
)

fun main() {
    // should print hello, prints {"value":"hello"}
    println(Json.encodeToString(RemoteMessage.StringType("hello")))
    // should print {"blahBlah":"hello"}, prints {"value":{"blahBlah":"hello"}}
    println(Json.encodeToString(RemoteMessage.ComplexType(ComplexClass("hello"))))
}
a

Adam S

10/05/2023, 9:38 PM
You can use a value class for
StringType
, then it should be encoded as a JSON string https://github.com/Kotlin/kotlinx.serialization/blob/v1.6.0/docs/value-classes.md#serializable-value-classes
f

franztesca

10/05/2023, 9:40 PM
I tried but "Value class cannot extend classes" 😞
a

Adam S

10/05/2023, 9:41 PM
Ahh right, you'll have to make the parent class a sealed interface instead
BTW I have a library that solves the problem in the other direction, and will generate Typescript from Kotlin. Maybe you don't want to use it, but it might help give some context https://adamko-dev.github.io/kotlinx-serialization-typescript-generator/docs/examples/polymorphism-sealed/#sealed-classes