本文介绍了使用 kotlinx.serialization 库反序列化具有不同值类型的 JSON 数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试反序列化以下字符串:

I'm trying to deserialize following String:

 val stringJson = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
   

使用以下代码反序列化效果很好

Deserialization works fine with following code

@Serializable
data class Artist(
    val decomposed: JsonArray
)

fun main() {
    val jsonString = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
    println(Json.decodeFromString<Artist>(jsonString))
}

但我想做类似的事情

@Serializable
class Decomposed {
    @Serializable
    class DecomposedClassValue(val value: DecomposedClass)

    @Serializable
    class StringValue(val value: String)
}


@Serializable
data class DecomposedClass(
    val id: Long? = null,
    val name: String? = null,
    val various: Boolean? = null,
    val composer: Boolean? = null,
    val genres: JsonArray? = null
)

@Serializable
data class Artist(
    val decomposed: List<Decomposed>
)

fun main() {
    val jsonString = "{\"decomposed\":[\", \",{\"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}"
    println(Json.decodeFromString<Artist>(jsonString))
}

但是 kotlinx.serialization 预计会失败,并出现 JsonDecodingException: 偏移量 15 处的意外 JSON 令牌:预期的 '{, kind: CLASS'而且我不知道如何重写我的 Decomposed 以便反序列化工作.你能帮我吗?

But kotlinx.serialization expectedly fails with JsonDecodingException: Unexpected JSON token at offset 15: Expected '{, kind: CLASS'And I can't figure out how can I rewrite my Decomposed so deserialization work. Can you please help me out?

推荐答案

您尝试做的事情叫做 多态反序列化.它要求反序列化的目标类有一个共同的超类(最好是密封的):

What you are trying to do is called polymorphic deserialization.It requires target classes of deserialization to have a common superclass (preferrably sealed):

@Serializable
data class Artist(
    val decomposed: List<Decomposed>
)

@Serializable
sealed class Decomposed

@Serializable
class StringValue(val value: String) : Decomposed() //Can't add superclass to String, so we have to create a wrapper class which we could make extend Decomposed

@Serializable
data class DecomposedClass(
    val id: Long? = null,
    val name: String? = null,
    val various: Boolean? = null,
    val composer: Boolean? = null,
    val genres: JsonArray? = null
) : Decomposed() //DecomposedClassValue is redundant, we may extend DecomposedClass from Decomposed directly

这将允许您反序列化以下格式的 JSON:

This will allow you to deserialize JSON of the following format:

val jsonString = "{\"decomposed\":[{\"type\":\"StringValue\", \"value\":\",\"}, {\"type\":\"DecomposedClass\", \"id\":4944372,\"name\":\"Johny\",\"various\":false,\"composer\":false,\"genres\":[]}]}" 

因为没有 类判别器 在原始 JSON 中,序列化库无法确定应该用于反序列化 Kotlin 类的实际序列化器.您必须编写自定义 JsonContentPolymorphicSerializer 并将其连接到 Decomposed 类;您还必须为 StringValue 类编写自定义序列化程序,因为它在 JSON 中表示为 String,而不是带有 value 字段的 JSONObjectString 类型:

Since there is no class descriminator in original JSON, serialization library can't determine the actual serializer which should be used to deserialize Kotlin class. You will have to write custom JsonContentPolymorphicSerializer and wire it to Decomposed class; also you have to write custom serializer for StringValue class, as it is represented in JSON as a String, not a JSONObject with a value field of String type:

object DecomposedSerializer : JsonContentPolymorphicSerializer<Decomposed>(Decomposed::class) {
    override fun selectDeserializer(element: JsonElement) = when {
        element is JsonPrimitive -> StringValue.serializer()
        else -> DecomposedClass.serializer()
    }
}

object StringValueSerializer : KSerializer<StringValue> {
    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("StringValue")

    override fun deserialize(decoder: Decoder): StringValue {
        require(decoder is JsonDecoder)
        val element = decoder.decodeJsonElement()
        return StringValue(element.jsonPrimitive.content)
    }

    override fun serialize(encoder: Encoder, value: StringValue) {
        encoder.encodeString(value.value)
    }
}

@Serializable(with = DecomposedSerializer::class)
sealed class Decomposed

@Serializable(with = StringValueSerializer::class)
class StringValue(val value: String) : Decomposed()

这将允许您反序列化原始格式的 JSON.

This will allow you to deserialize JSON of original format.

这篇关于使用 kotlinx.serialization 库反序列化具有不同值类型的 JSON 数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-19 01:47