为什么我在 kotlinx.serialization 中收到 JsonDecodingException 异常?

Why am I getting a JsonDecodingException exception in kotlinx.serialization?

我正在尝试使用 kotlinx.serialization 创建自定义反序列化器,但是当我反序列化带有空参数的 JSON 负载时,抛出异常 kotlinx.serialization.json.JsonDecodingException: Unexpected JSON token at offset 31: Expected string or non-null literal.。如果有任何英文错误,我深表歉意;如果缺少更多信息,请告诉我我将编辑 post.

注意:EventDecoder没有问题。

JSON:

{"t":null,"s":null,"op":11,"d":null}

异常:

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.emit(Collect.kt:136)
    at kotlinx.coroutines.flow.FlowKt__ChannelsKt.emitAllImpl$FlowKt__ChannelsKt(Channels.kt:58)
    at kotlinx.coroutines.flow.FlowKt__ChannelsKt$emitAllImpl.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)

代码:

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配置:

@OptIn(UnstableDefault::class)
val DiscordJsonParser = Json(
    JsonConfiguration(ignoreUnknownKeys = true, isLenient = true)
)

我的问题已经解决了。我忘了解码其中一个元素。

在我的例子中是这样的:

我试图将数据反序列化为非原始类型(这是一个数据 class),问题是序列化数据不是该数据的实例 class .

我已经序列化了一个 String 类型,但我正在将它反序列化为另一种类型。

在我的例子中,问题是在模型内的某些字段上使用了@SerializedName。因为注释中使用的名称与我收到此异常的字段名称不同。