You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android中Gson将API返回JsonObject转为List<ThingProperty>的方法

解决Retrofit2+Gson将JSON对象转为Kotlin列表的问题

问题场景

在Android开发中用Retrofit2调用API,通过Gson Converter序列化JSON到Kotlin对象时碰到问题:JSON里的properties字段是一个JSON对象(键为属性名称,值是对应属性结构),但我需要把它转成List<ThingProperty>——直接声明成List<ThingProperty>会报JsonSyntaxException(提示预期数组但实际是对象);声明成JsonObject能正常接收,但没法直接得到ThingProperty列表。

附properties字段JSON示例:

"properties":{
        "ActiveEvent":{
            "name":"ActiveEvent",
            "value":false,
            "visible":true,
            "title":"Active Event",
            "type":"boolean",
            "@type":"BooleanProperty",
            "readOnly":true,
            "links":[{
                "rel":"property",
                "href":"/things/hydroqc-Maison/properties/ActiveEvent"
                }]
            },
        "PreHeatEvent":{
            "name":"PreHeatEvent",
            "value":false,
            "visible":true,
            "title":"Pre-Heat Event",
            "type":"boolean",
            "@type":"BooleanProperty",
            "readOnly":true,
            "links":[{
                "rel":"property",
                "href":"/things/hydroqc-Maison/properties/PreHeatEvent"
                }]
            }
}

方法1:Map中转(最简单高效)

直接把数据类里的properties字段声明为Map<String, ThingProperty>,Gson会自动将JSON对象的键值对映射成Map,之后只需把Map的values转成List即可。

代码示例:

// 接口返回的顶层数据类
data class ThingResponse(
    // 其他字段...
    val properties: Map<String, ThingProperty>
)

// 业务代码中转成List
val propertyList: List<ThingProperty> = thingResponse.properties.values.toList()

方法2:自定义Gson TypeAdapter(自动转为List)

如果不想在业务代码里做Map转List的操作,想直接把JSON对象序列化成List<ThingProperty>,可以自定义TypeAdapter。

步骤1:实现TypeAdapter

class ThingPropertyListAdapter : TypeAdapter<List<ThingProperty>>() {
    private val gson = Gson()

    override fun write(out: JsonWriter, value: List<ThingProperty>?) {
        // 若不需要将List序列化为JSON对象,直接抛出不支持异常即可
        throw UnsupportedOperationException("不支持将List<ThingProperty>序列化为JSON对象")
    }

    override fun read(`in`: JsonReader): List<ThingProperty> {
        val propertyList = mutableListOf<ThingProperty>()
        `in`.beginObject()
        while (`in`.hasNext()) {
            // 跳过JSON对象的键名,只解析对应的值
            `in`.nextName()
            val property = gson.fromJson(`in`, ThingProperty::class.java)
            propertyList.add(property)
        }
        `in`.endObject()
        return propertyList
    }
}

步骤2:注册适配器到Gson,配置给Retrofit

val customGson = GsonBuilder()
    .registerTypeAdapter(
        object : TypeToken<List<ThingProperty>>() {}.type,
        ThingPropertyListAdapter()
    )
    .create()

val retrofit = Retrofit.Builder()
    .baseUrl(BASE_URL) // 替换成你的API地址
    .addConverterFactory(GsonConverterFactory.create(customGson))
    .build()

步骤3:数据类直接声明为List

data class ThingResponse(
    // 其他字段...
    val properties: List<ThingProperty>
)

补充:ThingProperty数据类注意事项

确保ThingProperty的字段和JSON属性完全匹配,比如JSON里的@type需要用@SerializedName标注:

data class ThingProperty(
    val name: String,
    val value: Any?, // value可能是布尔、字符串或null,用Any?接收
    val visible: Boolean,
    val title: String,
    val type: String,
    @SerializedName("@type")
    val typeAnnotation: String,
    val readOnly: Boolean,
    val links: List<Link>
)

data class Link(
    val rel: String,
    val href: String
)

内容的提问来源于stack exchange,提问作者arist0v

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 15:55:14