Thread
#serialization
    a

    alllex

    2 months ago
    I am at a loss trying to configure serialization of generics. I have a pretty simple setup:
    import kotlinx.serialization.*
    import kotlinx.serialization.json.Json
    
    @Serializable
    sealed class ApiResponse<T> {
        @Serializable
        @SerialName("result")
        data class Ok<T>(val result: T) : ApiResponse<T>()
    
        @Serializable
        @SerialName("error")
        data class Error<T>(val error: ErrorResponse) : ApiResponse<T>()
    }
    
    @Serializable
    data class VersionResponse(val version: String)
    
    @Serializable
    data class ErrorResponse(val description: String)
    
    fun main() {
        val data: ApiResponse<VersionResponse> = ApiResponse.Ok(VersionResponse("v42"))
        println(Json.encodeToString(data)) // prints {"type":"result","result":{"version":"v42"}}
    }
    The last line mentions the result I want to achieve:
    ApiResponse
    is discriminated using
    type
    , and the
    result
    field is just serialized as it is. However, running this with Kotlin 1.7.10 and kotlinx.serialization 1.3.3 (json jvm) produces this error:
    Exception in thread "main" kotlinx.serialization.SerializationException: Class 'VersionResponse' is not registered for polymorphic serialization in the scope of 'Any'.
    Mark the base class as 'sealed' or register the serializer explicitly.
    	at kotlinx.serialization.internal.AbstractPolymorphicSerializerKt.throwSubtypeNotRegistered(AbstractPolymorphicSerializer.kt:102)
    Could you please help figuring this out? I tried in many ways to configure polymorphic serialization, but none of them worked.
    r

    rocketraman

    2 months ago
    Try doing this:
    val format = Json {
        serializersModule = SerializersModule {
          polymorphic(Any::class) {
            subclass(VersionResponse::class)
          }
        }
      }
    
      val data: ApiResponse<VersionResponse> = ApiResponse.Ok(VersionResponse("v42"))
      println(format.encodeToString(data)) // prints {"type":"result","result":{"version":"v42"}}
    a

    alllex

    2 months ago
    Thank you for the response! It does work with your configuration of the
    seralizersModule
    . However, what it prints is not exactly what I need:
    {
      "type": "result",
      "result": {
        "type": "VersionResponse",
        "version": "v42"
      }
    }
    As you can see, it adds
    type
    inside
    result
    as well.
    r

    rocketraman

    2 months ago
    If its a generic type T, then how is the deserializer supposed to know what type it needs to deserialize without some kind of discriminator?
    If you only care about serialization, you probably need a custom
    Serializer