'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 |