在 Kotlin 中使用 Moshi 和 Retrofit 解析具有增量对象名称的 JSON

Posted

技术标签:

【中文标题】在 Kotlin 中使用 Moshi 和 Retrofit 解析具有增量对象名称的 JSON【英文标题】:Parsing JSON with Increment Object Name using Moshi and Retrofit in Kotlin 【发布时间】:2021-08-24 22:08:06 【问题描述】:

我通过类似这样的 API 获取 JSON。

如您所见,第一个对象名称是一个增量值。如何使用 moshi 处理数据类或接口中的变量对象名称? 对于“普通”JSON 文件,此代码有效。有没有办法让数据类对象名可变或者如何改变接口创建常量名?

数据类:

data class PhilipsHueLightsApi(
    val lightId: List<HueLight>
)

data class HueLight(
    val state: HueLightState,
    val swupdate: HueLightSwupdate,
    val type: String,
    val name: String,
    val modelid: String,
    val manufacturername: String,
    val productname: String,
    val capabilities: HueLightCapabilities,
    val config: HueLightConfig,
    val uniqueid: String,
    val swversion: String
)

data class HueLightState (
    val on: Boolean,
    val bri: Int,
    val hue: Int,
    val sat: Int,
    val effect: String,
    val xy: HueLightColorCode,
    val ct: Int,
    val alert: String,
    val colormode: String,
    val mode: String,
    val reachable: Boolean
)...

API 服务:

interface OpenPhilipsHueConnection 

    /**
     * A public interface that exposes the [getPhilipsHueLightsApi] method
     */
    interface OneCallApiConnection 
        /**
         * The @GET annotation indicates that endpoint will be requested with the GET HTTP method
         */
        @GET("/$API_GET/$USER_ID/$API_SELECTION")
        suspend fun getPhilipsHueLightsApi(): Response<PhilipsHueLightsApi>
    

    // Singleton
    object OpenPhilipsHueLightsApi 
        /**
         * Build the Moshi object with Kotlin adapter factory that Retrofit will be using.
         */
        private val moshi = Moshi.Builder()
            .add(KotlinJsonAdapterFactory())
            .build()

        /**
         * The Retrofit object with the Moshi converter.
         */
        private val retrofit = Retrofit.Builder()
            .addConverterFactory(MoshiConverterFactory.create(moshi))
            .baseUrl(BASE_URL)
            .build()

        val oneCallApi: OneCallApiConnection by lazy  retrofit.create(OneCallApiConnection::class.java) 
    


错误信息:

I/LightRepository: Failure: Required value 'lightId' missing at $

【问题讨论】:

不要在问题中使用代码截图,复制粘贴代码本身。 【参考方案1】:

问题在于您对PhilipsHueLightsApi 的定义是具有lightId 类型List&lt;HueLight&gt; 的一个属性的对象的定义,并且与JSON 不匹配。 你得到的 JSON 也是一个对象,但它有多个属性,名称恰好是数字,这里没有涉及列表(或 JSON 数组)。

使用Map&lt;String, HueLight&gt; 而不是PhilipsHueLightsApi 类可以更好地表示这种格式。 您可能应该尝试像这样定义您的 API:

suspend fun getPhilipsHueLightsApi(): Response<Map<String, HueLight>>

【讨论】:

感谢您的快速响应。遗憾的是它不起作用:I/LightRepository: Failure: Expected BEGIN_OBJECT but was BEGIN_ARRAY at path $.1.state.xy @Ohlsen 问题在你的模型中更深层次。您应该尝试理解错误消息,它确实包含您需要的所有信息。查看错误中的路径,您已将属性 xy 定义为 Kotlin 中的对象,但它是 JSON 中的列表。您也应该在 Kotlin 声明中解决这个问题。您已经在那里隐藏了 JSON 数组的内容,所以我无法提供详细信息,但它应该非常简单 你是对的。它现在正在工作。非常感谢你的支持!!这对我帮助很大。

以上是关于在 Kotlin 中使用 Moshi 和 Retrofit 解析具有增量对象名称的 JSON的主要内容,如果未能解决你的问题,请参考以下文章

Moshi 的 Kotlin 代码生成器有啥用?

如何在 moshi (kotlin) 中解析 LinkedHashMap

(Kotlin 中的 Moshi)@Json 与 @field:Json

如何使用带有 Kotlin 的 Room 和 moshi 持久化带有 JSON 数组的 JSON 对象

Moshi + Kotlin + SealedClass

对kotlin友好的现代 JSON 库 moshi 基本使用和实战