I’m trying to deserialize a simple sealed class (w...
# serialization
l
I’m trying to deserialize a simple sealed class (with one field called
__type
and another called
message
) from my api, modeled using Retrofit and a generic response such as
NetworkResponse<MyResponse, ErrorResponse>
, in which the
ErrorResponse
is the sealed class in question. Analysing the returned type with the debugger shows me that my generic response is
Copy code
UnknownError(error=kotlinx.serialization.json.internal.JsonDecodingException: Polymorphic serializer was not found for missing class discriminator ('null')
JSON input: {"__type":"UserLambdaValidationException","message":"..."})
I’m using v1.0.0-RC, and unsure how to proceed.
v
The default discriminator is
type
. If you use
Json { classDiscriminator = "__type" }
it will probably work properly
l
Thanks for answering! Now it does not show
('null')
anymore, but right now as
Copy code
(’UserLambdaValidationException
’)
. I probably wont be able to match all possible values of
__type
, so maybe I could use an
when()
expression with a custom
KSerializer
? I have:
Copy code
@Serializer(forClass = ErrorResponse::class)
object ErrorResponseSerializer : KSerializer<ErrorResponse> {
  override val descriptor = ErrorResponse.serializer().descriptor

  override fun deserialize(decoder: Decoder): ErrorResponse {
    val surrogate = decoder.decodeSerializableValue(ErrorResponse.serializer())
    return when (surrogate.__type) {
      "UsernameExistsException" -> {
        UserExistsErrorResponse(surrogate.message, surrogate.__type)
      }
      "UserNotFoundException" -> {
        UserNotFoundErrorResponse(surrogate.message, surrogate.__type)
      }
      else -> {
        UnknownErrorResponse(surrogate.message, surrogate.__type)
      }
    }
  }
}
and that would fit my needs. If I apply to my sealed class definition, as
Copy code
@Serializable(with = ErrorResponseSerializer::class)
sealed class ErrorResponse {
  @SerialName("message") abstract val message: String
  @SerialName("__type") abstract val __type: String
}
then the app crashes with StackOverflowError. I assume I’m misusing something around
Copy code
decoder.decodeSerializableValue(ErrorResponse.serializer())
but can’t figure out how to do it
v
The same message but with
('UserLambdaValidationException')
? Afair the discriminator by default has the FQCN. So if your class is in a package it doesn't match. But you can use
@SerialName
on the class to configure the discriminator value.
l
The same message but with (‘UserLambdaValidationException’)?
Exactly 😕 but I imagine there will always be a different
__type
that I haven’t modeled (I don’t have access to the server side). Would a custom Kserializer be a solution? how can I deserialize and inspect/compare values?
v
Maybe, but I have not enough experience with custom serializer to say, sorry.
l
thank you anyway, Bjorn! you already helped a lot 🙏
v
And as thanks you rape my name? :'''-(
It's Björn or Bjoern, not Bjorn
One important reason for an ascii-only nickname
l
apologies Björn 🙏
❤️ 1
p
There's a
JsonContentPolymorphicSerializer
stub provided builtin that seems like it would fit
eg this stub to choose a serializer based on a piece of the incoming JSON
l
That’s great! It worked perfectly, thank you Paul 🙌
👍 1