如何用Gson解析含数字键的JSON到Kotlin对象?
解决Gson解析动态数字键的JSON问题
我明白你遇到的困扰了——当JSON里出现动态变化的数字键时,常规的@SerializedName确实派不上用场,因为这个注解只能映射固定的键名,而你的Id数组里每个对象的键都是不确定的数字(1、2...)。下面我给你两种实用的解决方案,用Gson就能轻松搞定:
方案一:用Map快速处理动态键
这是最简洁的方法,直接用Map<String, Student>接收每个带数字键的对象,之后再转换成你想要的结构:
1. 定义基础数据类
首先定义存储学生信息的类,注意class是Kotlin的关键字,得用@SerializedName映射到合法的字段名:
data class Student( val name: String, @SerializedName("class") // 映射JSON里的"class"键 val className: String )
然后定义顶层的响应类,用List<Map<String, Student>>接收Id数组:
data class StudentResponse( val Id: List<Map<String, Student>> )
2. 解析并转换数据
解析后遍历Map,把动态数字键提取成你需要的字符串字段(比如studentId):
// 假设jsonString是你的JSON响应字符串 val gson = Gson() val response = gson.fromJson(jsonString, StudentResponse::class.java) // 转换成包含studentId的对象列表 val studentWithIdList = response.Id.flatMap { map -> map.entries.map { entry -> // 这里可以自定义你的目标对象 StudentWithId( studentId = entry.key, name = entry.value.name, className = entry.value.className ) } } // 自定义的目标数据类 data class StudentWithId( val studentId: String, val name: String, val className: String )
方案二:自定义TypeAdapter(更优雅的封装)
如果你不想暴露Map的细节,希望直接解析成自定义对象,可以写一个Gson的TypeAdapter来处理动态键的解析:
1. 定义目标数据类
直接定义包含studentId的类:
data class StudentEntry( val studentId: String, val name: String, @SerializedName("class") val className: String )
2. 编写TypeAdapter
这个适配器会读取动态数字键,并把它赋值给studentId字段:
class StudentEntryTypeAdapter(private val gson: Gson) : TypeAdapter<StudentEntry>() { override fun write(out: JsonWriter, value: StudentEntry?) { // 如果需要序列化可以实现,这里只处理解析,暂时空实现 out.beginObject() value?.let { out.name(it.studentId) gson.toJson(Student(it.name, it.className), Student::class.java, out) } out.endObject() } override fun read(`in`: JsonReader): StudentEntry { `in`.beginObject() // 读取动态数字键作为studentId val studentId = `in`.nextName() // 读取键对应的Student对象 val student = gson.fromJson<Student>(`in`, Student::class.java) `in`.endObject() return StudentEntry(studentId, student.name, student.className) } // 辅助的Student类 private data class Student(val name: String, @SerializedName("class") val className: String) }
3. 注册适配器并解析
创建Gson实例时注册适配器,然后直接解析成目标类:
val gson = GsonBuilder() .registerTypeAdapter(StudentEntry::class.java, StudentEntryTypeAdapter(Gson())) .create() // 顶层响应类 data class StudentResponse( val Id: List<StudentEntry> ) // 解析JSON val response = gson.fromJson(jsonString, StudentResponse::class.java) // 现在response.Id里的每个元素都是带studentId的StudentEntry对象了
为什么@SerializedName没用?
再强调下:@SerializedName是用来将固定的JSON键名映射到Kotlin类的字段名,而你的场景中键是动态变化的(每次可能是1、2、3...不同的数字),注解无法预知这些动态键,所以必须用Map或自定义适配器来处理。
内容的提问来源于stack exchange,提问作者Divyanshu
相关产品推荐
相关产品推荐

