I am at a loss trying to configure serialization o...
# serialization
a
I am at a loss trying to configure serialization of generics. I have a pretty simple setup:
Copy code
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:
Copy code
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
Try doing this:
Copy code
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
Thank you for the response! It does work with your configuration of the
seralizersModule
. However, what it prints is not exactly what I need:
Copy code
{
  "type": "result",
  "result": {
    "type": "VersionResponse",
    "version": "v42"
  }
}
As you can see, it adds
type
inside
result
as well.
r
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