在 kotlinx.serialization 中编码/解码 JSON“字符串”

Posted

技术标签:

【中文标题】在 kotlinx.serialization 中编码/解码 JSON“字符串”【英文标题】:Encode / decode JSON "string" in kotlinx.serialization 【发布时间】:2021-06-11 09:18:41 【问题描述】:

是否可以在自定义序列化程序中以字符串格式编码/解码任何有效的 json 对象。 例如下面的代码,但不让它序列化为 json 字符串,而是序列化为任何结构未知的有效 JSON?

object JsonObjectSerializer : KSerializer<JsonObject> 

    override val descriptor = PrimitiveSerialDescriptor("JsonObject", PrimitiveKind.STRING)

    override fun deserialize(decoder: Decoder): JsonObject =
        JsonObject(decoder.decodeString())

    override fun serialize(encoder: Encoder, value: JsonObject): Unit =
        encoder.encodeString(value.encode())


Out 会是这样的......


    "some": "data",
    "jsonObject": "\"this\": \"should not be a string\""

但想要的输出是..


    "some": "data",
    "jsonObject": "this": "should not be a string"

【问题讨论】:

您找到解决方案了吗?似乎杰克逊通过@JsonRawValue 注释提供了这个(至少在序列化方面),但我似乎在kotlinx.serialization 中找不到相同的。 @MichelePalmia 是的,可以使用 JsonElement 作为可序列化值github.com/Kotlin/kotlinx.serialization/blob/master/docs/… 【参考方案1】:

encoder.encodeJsonElement 可能会做你想做的事。

我自己在UnknownPolymorphicSerializer&lt;P, W&gt;的实现中使用encodeJsonElement

类型 [P] 的多态对象的序列化程序,它将运行时未知的扩展类型包装为类型 [W] 的实例。

我提取已知结构并包装未知结构。也许是一个与您所追求的类似的用例?具体细节和用例相当复杂,但记录在“UnknownPolymorphicSerializer: (De)serializing unknown types”中。

@InternalSerializationApi
override fun serialize( encoder: Encoder, value: P )

    // This serializer assumes JSON serialization with class discriminator configured for polymorphism.
    // TODO: It should also be possible to support array polymorphism, but that is not a priority now.
    if ( encoder !is JsonEncoder )
    
        throw unsupportedException
    
    getClassDiscriminator( encoder.json ) // Throws error in case array polymorphism is used.

    // Get the unknown JSON object.
    check( value is UnknownPolymorphicWrapper )
    val unknown = Json.parseToJsonElement( value.jsonSource ) as JsonObject

    // HACK: Modify kotlinx.serialization internals to ensure the encoder is not in polymorphic mode.
    //  Otherwise, `encoder.encodeJsonElement` encodes type information, but this is already represented in the wrapped unknown object.
    AccessInternals.setField( encoder, "writePolymorphic", false )

    // Output the originally wrapped JSON.
    encoder.encodeJsonElement( unknown )

附: AccessInternals 是我的一个预期实现,能够使用 kotlin reflect,JS 不支持,因为这是一个多平台库。

【讨论】:

以上是关于在 kotlinx.serialization 中编码/解码 JSON“字符串”的主要内容,如果未能解决你的问题,请参考以下文章

在 kotlinx.serialization 中编码/解码 JSON“字符串”

用 Javalin 框架中的 kotlinx.serialization 替换 Jackson

使用 Kotlinx.Serialization 解析嵌套的 JSON

如何使用 kotlinx.serialization 在 Ktor 中序列化 Web Socket Frame.text

kotlinx.serialization :如何解析为与 JSON 键的确切名称不同的变量名称

Ktor 与 Kmongo 和 kotlinx.serialization