使用 kotlin 序列化将 JSON 反序列化为 "non-stable" 值

Deserialize JSON with "non-stable" values using kotlin serialization

我没有很好地从 BE 结构化 JSON(我无法更改),它以前是用 moshi(针对该问题的自定义适配器)处理的。现在我正在尝试使用纯 kotlin 序列化,但如前所述,JSON 结构对我帮助不大。

{
   "foo": {
       "version":1,
       "mask": [
          {
             "values": [
                  { "bar": 1, ... }
              ]
           },
           {
             "values": [
                  "important text i guess"
              ]
           },
       ]
    }
}

现在你可以看到我的问题是 values 可以同时包含 objectstring。所有这些都应该解析成 kotlin,其中 values 看起来像这样:

data class Values(
  val bar: Int? = null,
  val text: String? = null,
  ...
)

理论上我可以改变本地实现,例如拆分 values class 之类的。 我已经尝试应用多态反序列化,但据我了解,如果 JSON 中没有设置 class 鉴别器,它无法识别 values 的两个后代之间的差异.

有什么好的建议吗?

更新

我试过的多态版本(以防我刚刚犯了一些错误)

@Polymorphic
@Serializable
sealed class Values{
  
  @Serializable
  data class ObjectValues(
    val bar: Int? = null,
    ...
  )

  @Serializable
  data class TextValues(
    val text: String? = null
  )

}

并使用它:

Json {
        ignoreUnknownKeys = true
        serializersModule = SerializersModule {
            polymorphic(Values::class) {
                subclass(Values.ObjectValues::class, Values.ObjectValues.serializer())
                subclass(Values.TextValues::class, Values.TextValues.serializer())
            }
        }

错误:

Polymorphic serializer was not found for missing class discriminator ('null')
JSON input: {"bar":42,...}

免责声明 我知道这会解决所有问题:)

"values": [ { "text":"important text i guess" } ]

classDiscriminator 不是多态反序列化的强制要求。在这种情况下,您可以使用 content-based polymorphic deserialization

您只需要为 Values class 定义一个 JsonContentPolymorphicSerializer,并使用一些逻辑来精确选择子 class 序列化器:

object ValuesSerializer : JsonContentPolymorphicSerializer<Values>(Values::class) {
    override fun selectDeserializer(element: JsonElement) = when {
        element.jsonObject["values"]!!.jsonArray.first() is JsonObject -> ObjectValues.serializer()
        else -> TextValues.serializer()
    }
}

并将其连接为 Values class:

的序列化程序
@Serializable(with = ValuesSerializer::class)
sealed class Values

@Serializable
data class TextValues(val values: List<String>) : Values()

@Serializable
data class ObjectValues(val values: List<Bar>) : Values()

@Serializable
data class Bar(val bar: Int)

@Serializable
data class MyJson(val foo: Foo)

@Serializable
data class Foo(val version: Int, val mask: List<Values>)

不需要serializersModule:

val result = Json.decodeFromString<MyJson>(json)