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

sph*_*rak 5 android json adapter kotlin moshi

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

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

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

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

{
  # List<Warning>
  "warnings": [{...}, {...}]
}
Run Code Online (Sandbox Code Playgroud)

或像这样:

{
  # Warning
  "warnings": {...}
}
Run Code Online (Sandbox Code Playgroud)

我已经阅读并找到了有关此主题的一些资源,但没有示例,而且我不确定如何进行操作。因此,任何指针将不胜感激。

尝试

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

编辑:这是我目前拥有的,尽管我对Moshi实例正常工作并不满意。

工厂通用方法

自从我意识到像Eric在他的答复中指出的那样,更通用的方法更好之后,我便尝试移植Eric写给kotlin的适配器。一旦这有效,我将重新编写这篇文章的一部分,使其更易于理解,为此我为此表示歉意。

编辑:我最终在另一个线程中使用了Eric建议的解决方案,但移植到Kotlin。

带工厂适配器

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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

预选赛

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

@Retention(RUNTIME)
@Target(FIELD)
@JsonQualifier
annotation class SingleToArray
Run Code Online (Sandbox Code Playgroud)

用法

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

data class Alert(
    @SingleToArray
    @Json(name = "alert")
    val alert: List<Warning>
)
Run Code Online (Sandbox Code Playgroud)

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

val moshi = Moshi.Builder()
            .add(SingleToArrayAdapter.INSTANCE)
            .build()
Run Code Online (Sandbox Code Playgroud)

相关问题/主题:

Eri*_*ran 4

如果只有 1 个对象,API 将返回 1 个对象,或者返回 > 1 个对象列表。

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

这里还有另一个处理多种格式的例子供进一步阅读。