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
相关产品推荐
相关产品推荐

