【问题标题】:Kotlin Deserialization - JSON Array to multiple different objectsKotlin 反序列化 - 多个不同对象的 JSON 数组
【发布时间】:2021-01-30 03:43:23
【问题描述】:

我正在使用 kotlin serialization 的 1.0.0 版本,但是当我尝试反序列化“灵活”数组时遇到了问题。

从我无法控制的后端 API 中,我得到一个包含不同类型对象的 JSON 数组。您将如何使用 kotlin 序列化对它们进行反序列化?

例子

这是 API 的响应

[
  {
    "id": "test",
    "person": "person",
    "lastTime": "lastTime",
    "expert": "pro"
  },
  {
    "id": "test",
    "person": "person",
    "period": "period",
    "value": 1
  }
]
@Serializable
sealed class Base {
  @SerialName("id")
  abstract val id: String
  @SerialName("person")
  abstract val person: String
}

@Serializable
data class ObjectA (
 @SerialName("id") override val id: String,
 @SerialName("title") override val title: String,
 @SerialName("lastTime") val lastTime: String,
 @SerialName("expert") val expert: String
) : Base()

@Serializable
data class ObjectB (
 @SerialName("id") override val id: String,
 @SerialName("title") override val title: String,
 @SerialName("period") val period: String,
 @SerialName("value") val value: Int
) : Base()


执行以下代码会导致错误

println(Json.decodeFromString<List<Base>>(json))

错误Polymorphic serializer was not found for class discriminator

【问题讨论】:

    标签: android kotlin serialization deserialization heterogeneous-array


    【解决方案1】:

    当您说您不控制 API 时,JSON 是由 Kotlin 序列化库从您的代码生成的吗?还是您想将其融入您自己的类型中?

    默认情况下,密封类是 handled by adding a type field to the JSON,您的对象中有它,但它是您的 Base 类中的一个属性。在下一个示例中,它将向您展示如何添加 @SerialName("owned") 注释来说明每个类对应的 type 值,如果您可以将正确的值添加到您的类中,这可能会对您有所帮助?尽管在您的 JSON 示例中,两个对象都将“类型”作为它们的 type...

    如果您无法将 API 响应推送到正确的位置,您可能必须编写 custom serializer(这是您关心的反序列化部分)来解析事物并识别每个对象的样子,并构造适当的一个。

    (我对图书馆什么的了解不多,只是想给你一些东西看看,看看有没有帮助!)

    【讨论】:

    • 感谢您的回复!我想让你知道type 是纯粹的虚场作为例子。我在没有 type 的情况下编辑了我的问题 - 这个 JSON 来自后端 API。所以我无法将 API 响应推到正确的位置!我想我需要编写一个自定义序列化程序!我去看看:)
    • 如果对象中有一些标识符明确地将其标记为一类或另一类(即使名称错误),那么@SerialName 注释应该起作用吗?如果没有什么可以识别它并且您基本上必须从字段中推断出它,那么是的,我认为您可能需要自己编写该逻辑!
    【解决方案2】:

    @cactustictacs 解决方案非常接近。他说“默认情况下,密封类是通过向 JSON 添加类型字段来处理的”

    但是因为我没有 type 属性,所以我需要一个其他字段来决定它应该是哪个子类。

    在 Kotlin 序列化器中,您可以这样做

     val format = Json {
        classDiscriminator = "PROPERTY_THAT_DEFINES_THE_SUBCLASS"
     }
     val contentType = MediaType.get("application/json")
     val retrofit = Retrofit.Builder()
                    .baseUrl(baseUrl)
                    .client(client)
                    .addConverterFactory(format.asConverterFactory(contentType))
                    .build()
    

    classDiscriminator 中,您可以输入所需的属性。希望这对将来的其他人有所帮助。

    【讨论】:

      猜你喜欢
      • 2012-06-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-27
      • 1970-01-01
      • 1970-01-01
      • 2015-06-11
      相关资源
      最近更新 更多