【问题标题】:Moshi + Retrofit - Handling JSON response of unknown typeMoshi + Retrofit - 处理未知类型的 JSON 响应
【发布时间】:2020-09-22 18:48:18
【问题描述】:

我正在使用 Moshi,我有以下数据类

@JsonClass(generateAdapter = true)
data class A (
    @Json(name = "_id")
    val id: String?,
    @Json(name = "b")
    val b: B? = null
)

@JsonClass(generateAdapter = true)
data class B (
    @Json(name = "_id")
    val id: String?,
    @Json(name = "foo")
    val foo: String? = null
    @Json(name = "c")
    val c: C? = null
)

@JsonClass(generateAdapter = true)
data class C (
    @Json(name = "_id")
    val id: String?,
    @Json(name = "bar")
    val bar: String? = null
)

我的 API 有时将对象仅作为 ID 返回,而其他时候将其作为实际对象返回。例如,有时当我获取对象 A 时,它会返回

{
    _id: "111111111",
    b: {
        _id: "222222222",
        foo: "foo",
        c: {
            _id: "333333333",
            bar: "bar"
        }
    }
}

但其他时候它可能会返回

{
    _id: "111111111",
    b: "222222222"
}

{
    _id: "111111111",
    b: {
        _id: "222222222",
        foo: "foo",
        c: "333333333"
    }
}

如我们所见,它可能会返回一个表示对象的字符串,或填充的对象本身。如何创建自定义 Moshi 适配器来处理这个问题?如果它返回一个表示对象的 id,我希望它创建一个仅填充 id 并将其余字段设置为 null 的对象。

我尝试像这样创建一个自定义适配器

class bAdapter {
    @FromJson
    fun fromJson(b: Any): B {
        return when (b) {
            is String -> B(b)
            else -> b as B
        }
    }
}

但我得到了错误

com.squareup.moshi.JsonDataException: java.lang.ClassCastException: com.squareup.moshi.LinkedHashTreeMap cannot be cast to com.example.B

【问题讨论】:

    标签: android json kotlin retrofit moshi


    【解决方案1】:

    如果有人遇到同样的问题,我通过使用漂亮的 @JsonQualifier 注释来解决它,如下所示:

    @Retention(AnnotationRetention.RUNTIME)
    @JsonQualifier
    internal annotation class ObjectString
    
    class ObjectStringAdapter {
        @FromJson
        @ObjectString
        fun fromJson(id: String): Object {
            return Object(id)
        }
    
        @ToJson
        fun toJson(@ObjectString obj: Object): String {
            return obj.toString()
        }
    }
    
    class ObjectAdapter {
        @FromJson
        fun fromJson(jsonReader: JsonReader, @ObjectString stringAdapter: JsonAdapter<Object>, defaultAdapter: JsonAdapter<Object>): Object {
            return when (JsonReader.Token.STRING) {
                jsonReader.peek() -> {
                    stringAdapter.fromJson(jsonReader)
                }
                else -> {
                    defaultAdapter.fromJson(jsonReader)
                }
            }!!
        }
    }
    

    Object 是你的班级。

    基本上创建了两个适配器,一个用于字符串,一个用于对象,并使用 jsonReader.peek() 来查看值并在运行时根据类型确定使用哪一个。

    供参考:Moshi LocalDateTime adapter with multiple format

    【讨论】:

      猜你喜欢
      • 2020-05-14
      • 2020-05-15
      • 1970-01-01
      • 2018-02-16
      • 1970-01-01
      • 2016-07-02
      • 2020-04-19
      • 2015-05-03
      • 1970-01-01
      相关资源
      最近更新 更多