首页 > 解决方案 > 改造 Moshi 如何将具有不同字段的对象数组转换为 POJO

问题描述

我很难考虑如何将以下 JSON 转换为 Moshi 数据类。我也无法更改 API 的工作方式,因为 API 不是我的。

JSON在下面:

{
            "relationships": [
                {
                    "id": "66a36824-04e6-452c-b9d2-679ac589cb8a",
                    "type": "artist",
                    "attributes": {
                        "name": "Nyunyu",
                        "imageUrl": null,
                        "biography": [],
                        "createdAt": "2021-04-19T21:59:45+00:00",
                        "updatedAt": "2021-04-19T21:59:45+00:00",
                        "version": 1
                    }
                },
                {
                    "id": "a050afdf-7377-4fe6-8317-fe7b38d1e000",
                    "type": "cover_art",
                    "attributes": {
                        "description": "",
                        "volume": null,
                        "fileName": "b0d63a0b-dd95-468c-b3e1-098e1414f6e9.jpg",
                        "createdAt": "2021-05-24T18:35:46+00:00",
                        "updatedAt": "2021-05-24T18:35:46+00:00",
                        "version": 1
                    }
                }
            ]
}

我发现不可能转换,因为如果你有一个相同对象的数组,那么每个对象必须共享相同的结构对!但在这种情况下,我被迫这样做。请注意,它们具有完全不同的字段。

@JsonClass(generateAdapter = true)
data class Attributes (
   @Json(name = "name") val name : String,
   @Json(name = "imageUrl") val imageUrl : String,
   @Json(name = "biography") val biography : List<String>,
   @Json(name = "createdAt") val createdAt : String,
   @Json(name = "updatedAt") val updatedAt : String,
   @Json(name = "version") val version : Int
)

@JsonClass(generateAdapter = true)
data class Attributes (
   @Json(name = "description") val description : String,
   @Json(name = "volume") val volume : String,
   @Json(name = "fileName") val fileName : String,
   @Json(name = "createdAt") val createdAt : String,
   @Json(name = "updatedAt") val updatedAt : String,
   @Json(name = "version") val version : Int
)

当然,它不能编译,因为我们不能有两个同名的类。那么在这种情况下我该怎么办呢?

标签: androidjsonkotlinretrofit

解决方案


您需要一个 Moshi 自定义转换器,可能需要创建 2 个类,ArtistAttributes它们CoverArtAttributes从基Attributes类继承了它们的一些公共属性。然后在自定义转换器中检查 type json 属性,如果等于则covert_art创建 CoverArtAttributes 对象,否则创建另一个。

然后在你的父类中,你应该有类似的东西:

data class Relationship constructor (
   @Json(name = "id") val id : String,
   @Json(name = "type") val type : String,
   @Json(name = "attributes") val attributes : Attributes,
)
class AttributesAdapter {
  @ToJson
  fun toJson(Attributes attributes): String {
    //ignore if you don't need opposite conversion
  }

  @FromJson
  fun fromJson(String json): Attributes {
    val moshi = Moshi.Builder().build()
    val jsonObject = JSONObject(json)
    val type = jsonObject.getString("type")
    val adapter = when (type) {
      "artist" -> { 
        moshi.adapter(ArtistAttributes::class.java)
      }
      "cover_art" -> { 
        moshi.adapter(CoverArtAttributes::class.java)
      }
      else -> throw IllegalArgumentException("unhandled type")
    }
    return adapter.fromJson(json)
  }
}

然后你需要添加AttributesAdapter到父 Moshi 实例并使用它来转换 JSON。

PS:以上代码未经测试,您可能需要进行调整才能使其正常工作,但它可以给您一些提示。

有关此主题的更多信息,请Moshi custom adapters在 Internet 上搜索,周围有一些有用的资源


推荐阅读