Moshi:解析单个对象或对象列表(kotlin)

时间:2018-11-16 19:12:41

标签: android json kotlin adapter moshi

我正在构建一个应用程序,该应用程序可以从我无法控制的API中获取Warning对象,他们也不希望删除我正在尝试解决的这种行为。

我希望能够解析单个Warning对象或List<Warning>对象。 (因为如果一个对象列表只有1个或1个以上,API会返回1个对象。)

问题

如何直接将对象解析为列表或使用Moshi解析此列表?

我得到的数据看起来像这样:

{
  # List<Warning>
  "warnings": [{...}, {...}]
}

或类似这样:

{
  # Warning
  "warnings": {...}
}

我已阅读并找到了有关此主题的一些资源,但没有示例,而且我不确定如何进行操作。.所以任何指针都将受到高度赞赏。

尝试

最初,我尝试用自动生成的moshi适配器拔钉子,以为我可以在其上构建它,但是我不知道发生了什么,因此它并没有真正带我到任何地方。但是无论如何我都会包含生成的代码,以防它可能仍然对任务有用。

编辑:这是我目前拥有的,尽管我对使用Moshi实例起作用的事实并不满意。

解决方案

工厂通用方法

我试图移植Eric写给kotlin的适配器 自从我意识到一种更通用的方法就像 埃里克(Eric)在他的答复中指出。一旦这有效,我将重新编写这篇文章的一部分,使其更易于理解,为此我为此表示歉意。

编辑:我最终在另一个线程中使用了solution埃里克(Eric)建议,但移植到了Kotlin。

带有Factory的适配器

class SingleToArrayAdapter(
    val delegateAdapter: JsonAdapter<List<Any>>,
    val elementAdapter: JsonAdapter<Any>
) : JsonAdapter<Any>() {

    companion object {
        val INSTANCE = SingleToArrayAdapterFactory()
    }

    override fun fromJson(reader: JsonReader): Any? =
        if (reader.peek() != JsonReader.Token.BEGIN_ARRAY) {
            Collections.singletonList(elementAdapter.fromJson(reader))
        } else delegateAdapter.fromJson(reader)

    override fun toJson(writer: JsonWriter, value: Any?) =
        throw UnsupportedOperationException("SingleToArrayAdapter is only used to deserialize objects")

    class SingleToArrayAdapterFactory : JsonAdapter.Factory {
        override fun create(type: Type, annotations: Set<Annotation>, moshi: Moshi): JsonAdapter<Any>? {
            val delegateAnnotations = Types.nextAnnotations(annotations, SingleToArray::class.java)
            if (delegateAnnotations == null) return null
            if (Types.getRawType(type) != List::class.java) throw IllegalArgumentException("Only lists may be annotated with @SingleToArray. Found: $type")
            val elementType = Types.collectionElementType(type, List::class.java)
            val delegateAdapter: JsonAdapter<List<Any>> = moshi.adapter(type, delegateAnnotations)
            val elementAdapter: JsonAdapter<Any> = moshi.adapter(elementType)

            return SingleToArrayAdapter(delegateAdapter, elementAdapter)
        }
    }
}

预选赛

注意:我必须添加Target(FIELD)

@Retention(RUNTIME)
@Target(FIELD)
@JsonQualifier
annotation class SingleToArray

用法

@SingleToArray注释要确保被解析为列表的字段。

data class Alert(
    @SingleToArray
    @Json(name = "alert")
    val alert: List<Warning>
)

不要忘记将适配器添加到您的moshi实例:

val moshi = Moshi.Builder()
            .add(SingleToArrayAdapter.INSTANCE)
            .build()

相关问题/主题:

1 个答案:

答案 0 :(得分:2)

  

如果对象列表只有1个,则API返回1个对象。

创建一个适配器,以窥视是否首先获得阵列。 Here正是您想要的。它包含一个限定符,因此您只能将其应用于可能对单个项目具有此行为的列表。 @SingleToArray List<Warning>

还有另一个处理多种格式here以供进一步阅读的示例。