'Why am I getting a JsonDecodingException exception in kotlinx.serialization?
I'm trying to create a custom deserializer using kotlinx.serialization but when I deerialize a JSON payload with null parameters, an exception kotlinx.serialization.json.JsonDecodingException: Unexpected JSON token at offset 31: Expected string or non-null literal. is threw. I apologize if there is any English error; if more information is missing, just let me know that I will edit the post.
Note: There is nothing wrong with the EventDecoder.
JSON:
{"t":null,"s":null,"op":11,"d":null}
Exception:
16:56:45.012 [main] ERROR io.github.discordkt.common.gateway.Gateway - Unexpected JSON token at offset 31: Expected string or non-null literal.
 JSON input: {"t":null,"s":null,"op":11,"d":null}
kotlinx.serialization.json.JsonDecodingException: Unexpected JSON token at offset 31: Expected string or non-null literal.
 JSON input: {"t":null,"s":null,"op":11,"d":null}
    at kotlinx.serialization.json.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:26)
    at kotlinx.serialization.json.internal.JsonReader.fail(JsonReader.kt:311)
    at kotlinx.serialization.json.internal.JsonReader.takeString(JsonReader.kt:142)
    at kotlinx.serialization.json.internal.StreamingJsonInput.decodeString(StreamingJsonInput.kt:179)
    at kotlinx.serialization.json.internal.StreamingJsonInput.decodeObjectIndex(StreamingJsonInput.kt:115)
    at kotlinx.serialization.json.internal.StreamingJsonInput.decodeElementIndex(StreamingJsonInput.kt:88)
    at io.github.discordkt.core.events.EventDeserializer.deserialize(EventDeserializer.kt:56)
    at io.github.discordkt.core.events.EventDeserializer.deserialize(EventDeserializer.kt:29)
    at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:52)
    at kotlinx.serialization.json.internal.StreamingJsonInput.decodeSerializableValue(StreamingJsonInput.kt:33)
    at kotlinx.serialization.DecodingKt.decode(Decoding.kt:521)
    at kotlinx.serialization.json.Json.parse(Json.kt:131)
    at io.github.discordkt.core.gateway.ws.DiscordGatewayListener.onMessageReceived(DiscordGatewayListener.kt:54)
    at io.github.discordkt.core.gateway.ws.DiscordGatewayAdapter$setupSession$$inlined$collect$1.emit(Collect.kt:136)
    at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt(Channels.kt:58)
    at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl$1.invokeSuspend(Channels.kt)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:56)
    at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:274)
    at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:84)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
    at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
    at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
    at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
    at OiKt.main(Oi.kt:14)
    at OiKt.main(Oi.kt)
Code:
object EventDeserializer: DeserializationStrategy<Event?> {
    override val descriptor = SerialDescriptor("Event") {
        /** The `op` field represents the [GatewayCode] that is used to identify the event type. */
        element("op", GatewayCode.descriptor, isOptional = false) // Index 0
        /** The `t` field represents the gateway event name. */
        element("t", nullable<String>().descriptor, isOptional = true) // Index 1
        /** The `s` field represents the sequence number that is used to resume the connection. */
        element("s", nullable<Int>().descriptor, isOptional = true) // Index 2
        /** The `d` field represents a [JsonObject] that includes the event data. */
        element("d", nullable<JsonObject>().descriptor, isOptional = false) //Index 3
    }
    override fun deserialize(decoder: Decoder): Event? {
        var code: GatewayCode = GatewayCode.UNKNOWN
        var eventName: String? = null
        var sequence: Int? = null
        var event: Event? = null
        with(decoder.beginStructure(descriptor)) {
            loop@ while(true) {
                when(val index = decodeElementIndex(descriptor)) {
                    CompositeDecoder.READ_DONE -> break@loop
                    0 -> code = decodeSerializableElement(descriptor, index, GatewayCode).also(::println)
                    1 -> eventName = decodeNullableSerializableElement(descriptor, index, nullable<String?>())
                    2 -> sequence = decodeNullableSerializableElement(descriptor, index, nullable<Int?>())
                    3 -> event = when(code) {
                        GatewayCode.DISPATCH -> EventDecoder(this, descriptor, eventName, index, sequence)
                        GatewayCode.INVALID_SESSION -> EventDecoder.INVALID_SESSION(this, descriptor, index)
                        GatewayCode.HANDSHAKE -> EventDecoder.HANDSHAKE_MESSAGE(this, descriptor, index)
                        GatewayCode.HEARTBEAT_ACK -> HeartbeatAckEvent
                        GatewayCode.HEARTBEAT -> HeartbeatOrderEvent
                        GatewayCode.RECONNECT -> ReconnectOrderEvent
                        else -> null
                    }
                }
            }
            endStructure(descriptor)
            return event
        }
    }
    override fun patch(decoder: Decoder, old: Event?): Event? {
        throw UpdateNotSupportedException(descriptor.serialName)
    }
    @OptIn(ExperimentalStdlibApi::class)
    @Suppress("UNCHECKED_CAST")
    private inline fun <reified T> nullable(): KSerializer<T?> {
        return serializer(typeOf<T?>()) as KSerializer<T?>
    }
}
JSON configuration:
@OptIn(UnstableDefault::class)
val DiscordJsonParser = Json(
    JsonConfiguration(ignoreUnknownKeys = true, isLenient = true)
)
Solution 1:[1]
In my case it was like this : 
I was trying to deserialize a data to a non-primitive type (which was a data class) and the problem was that the serialized data, was not an instance of that data class.
I had serialized a String type but I was deserializing it to another type.
Solution 2:[2]
In my case the problem was using @SerializedName on some of fields inside the model. Because the name used inside the annotation was different than the field name I was getting this exception.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source | 
|---|---|
| Solution 1 | Mahdi nezam parast | 
| Solution 2 | Reza | 
