Android Kotlin:含不确定键的JSON转Data Class时Map字段为空求助
解决方案
你的问题核心是JSON采用了混合结构:既有固定字段className,又有动态数字键("0"、"1")对应EachClass对象,而Gson默认无法自动将这些动态键映射到Orders类的classes属性上,导致classes始终为null。下面是两种优雅的解决方法:
方法一:自定义Json反序列化器
保持你现有的Data Class结构不变,通过实现JsonDeserializer来手动处理JSON字段的映射逻辑:
1. 实现反序列化器
import com.google.gson.* import java.lang.reflect.Type class OrdersDeserializer : JsonDeserializer<Orders> { override fun deserialize( json: JsonElement?, typeOfT: Type?, context: JsonDeserializationContext? ): Orders { val jsonObject = json?.asJsonObject ?: throw JsonParseException("无效的JSON格式") var className: String? = null val classesMap = mutableMapOf<String, EachClass>() val gson = Gson() // 遍历JSON所有键值对 for ((key, value) in jsonObject.entrySet()) { when (key) { "className" -> className = value.asString else -> { // 将动态键对应的JSON对象转为EachClass实例 val eachClass = gson.fromJson(value, EachClass::class.java) classesMap[key] = eachClass } } } return Orders(className, classesMap) } }
2. 注册反序列化器并反序列化
创建Gson实例时注册自定义的反序列化器,然后正常解析JSON:
val gson = GsonBuilder() .registerTypeAdapter(Orders::class.java, OrdersDeserializer()) .create() // 假设jsonString是你的原始JSON字符串 val orders = gson.fromJson(jsonString, Orders::class.java)
方法二:使用@JsonAdapter注解简化注册
如果你不想每次创建Gson实例都手动注册反序列化器,可以直接在Orders类上添加@JsonAdapter注解,让Gson自动识别:
import com.google.gson.annotations.JsonAdapter @JsonAdapter(OrdersDeserializer::class) data class Orders ( val className: String?, val classes: Map<String, EachClass> ) data class EachClass ( val id: String, val type: String, val items: List<Person> ) data class Person ( val name: String, val value: String, val age: String )
之后直接使用默认Gson实例即可完成解析:
val orders = Gson().fromJson(jsonString, Orders::class.java)
为什么原有方案失效?
Gson的默认映射规则是严格匹配字段名:你的Orders类定义了classes属性,但原始JSON中并没有名为classes的字段,那些动态数字键无法自动被识别为classes的Map元素,因此classes始终为null。自定义反序列化器的作用就是手动将这些动态键值对收集到classesMap中,同时保留className字段的映射。
内容的提问来源于stack exchange,提问作者JackWu
相关产品推荐
相关产品推荐

