【问题标题】:How can I convert empty objects as null with moshi and retrofit?如何使用 moshi 和改造将空对象转换为 null?
【发布时间】:2019-05-14 17:41:14
【问题描述】:

我在 Kotlin 中使用 retrofit2 + Moshi 连接到服务器。

所有响应都用 result 属性包装。我创建了一个通用数据类,如下所示

@JsonClass(generateAdapter = true)
data class CommonResponse<T>(val result: T?)

如果结果属性不为空,例如:

{
    "result": {
        "bar": 1
    }
}

拥有一个数据类 Foo 并在 Foo 中使用泛型

data class Foo(val bar: Int)

interface {

    @Path("/foo")
    fun getFoo(): CommonResponse<Foo>
}

但是如果result属性为空如下

{
  "result": {}
}

由于 bar 不能为空,我收到 JsonDataException。

对于结果属性为空的情况,是否有任何方法将其视为空使用通用适配器

到目前为止,我所做的是捕获 JsonDataException 异常并在这些情况下返回 null,但我对这个解决方案不满意,因为结果 w/o 数据是有效响应。此外,我无法区分没有结果的响应或无效响应。

有什么想法吗?

注意:我无法修改服务器响应。

【问题讨论】:

    标签: android retrofit2 moshi


    【解决方案1】:

    有什么办法可以让result属性为空的情况下认为是null?

    是的,您需要使属性栏为空,因为这是Int? 的例外情况,并为该属性添加一个默认值,因此如果它不存在,则可以将其设置为空。所以把data class Foo(val bar: Int)改成data class Foo(val bar: Int? = null)

    这将为以下 JSON 设置 bar 为 null:

    {
        "result": {
            "bar": null
        }
    }
    

    ...和

    {
        "result": {}
    }
    

    【讨论】:

    • 感谢您的评论,但“bar”不能为空。这是我问题的关键
    • 我关于创建自定义适配器的其他答案是否有帮助?谢谢
    • 这个想法是创建一个通用适配器,而不是针对特定响应。这就是为什么你的回答对我来说不正确
    【解决方案2】:

    如果 JSON 为空,要将结果设置为 null,您需要为 CommonResponse 创建自己的自定义适配器。所以首先你不需要为 CommonResponse 生成适配器:

    data class CommonResponse<T>(val result: T?)
    data class Foo(val bar: Int)
    

    ...然后您需要为 Foo 类型的 CommonResponse 创建一个自定义适配器:

    class CommonResponseAdapterFoo {
    
        @FromJson
        fun fromJson(reader: JsonReader): CommonResponse<Foo>{
            var fooObj: Foo? = null
    
            while (reader.hasNext()) {
                reader.beginObject()
                if (reader.nextName() == "result") {
                    reader.beginObject()
                    if (reader.hasNext()) {
                        if (reader.nextName() == "bar") {
                            val barValue = reader.nextInt()
                            fooObj = Foo(barValue)
                        }
                    }
                    reader.endObject()
    
                }
                reader.endObject()
            }
    
            return CommonResponse(fooObj)
        }
    }
    

    ...然后您需要将此自定义适配器添加到您的 moshi 实例中:

    val moshi = Moshi.Builder().add(CommonResponseAdapterFoo()).build()
    

    如果您在 CommonResponse 中包装多个类型,那么您可能需要创建多个自定义适配器来适应所有不同的类型

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-03
      • 1970-01-01
      • 2020-09-26
      • 2021-05-13
      相关资源
      最近更新 更多