为什么我在 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。因为注释中使用的名称与我收到此异常的字段名称不同。
我正在尝试使用 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。因为注释中使用的名称与我收到此异常的字段名称不同。