如何用Gson将JSON映射到含嵌套包装子类的Kotlin数据类?
问题
我正在为GraphQL解析器编写单元测试,遇到JSON与Kotlin数据类的映射不匹配问题,具体情况如下:
JSON结构
{ "data": { "myVar": { "myArray": [{ "someVal": "someStr1", "myVal": "myStr1", }, { "someVal": "someStr2", "myVal": "myStr2" } ] } } }
Kotlin数据类定义
data class MyDataClass( myVar: MyBaseVar? = null ) data class MyBaseVar( myArray: List<MyArrayListValue>? = null ) data class MyArrayListValue( someVal: String? = null, myPersonalData: MyPersonalData? = null ) data class MyPersonalData( // 包裹myVal的类 myVal: String? = null )
原解析代码
val jsonData = JsonParser.parseString( javaClass.getResourceAsStream(myJsonFile)!!.reader().readText() ).asJsonObject.get("data") val myParsedData = Gson().fromJson(jsonData, MyDataClass::class.java)
问题核心
JSON中的data.myVar.myArray[x].myVal字段,无法自动映射到数据类的myParsedData.myVar.myArray[x].myPersonalData.myVal,导致该字段始终为null。我不能修改现有的JSON结构和数据类,需要一种无需手动遍历节点创建实例的映射方案。
解决方案
使用Gson的自定义TypeAdapter可以解决这个字段嵌套映射的问题,具体实现如下:
1. 编写MyArrayListValue的TypeAdapter
这个适配器会在反序列化时,将JSON中的myVal字段提取并封装到MyPersonalData实例中,再赋值给MyArrayListValue的对应属性:
class MyArrayListValueAdapter : TypeAdapter<MyArrayListValue>() { override fun write(out: JsonWriter, value: MyArrayListValue?) { // 若需要序列化可在此实现,本文仅处理反序列化逻辑 out.beginObject() value?.someVal?.let { out.name("someVal").value(it) } value?.myPersonalData?.myVal?.let { out.name("myVal").value(it) } out.endObject() } override fun read(`in`: JsonReader): MyArrayListValue { var someVal: String? = null var myVal: String? = null `in`.beginObject() while (`in`.hasNext()) { when (`in`.nextName()) { "someVal" -> someVal = `in`.nextString() "myVal" -> myVal = `in`.nextString() else -> `in`.skipValue() // 忽略未定义的字段 } } `in`.endObject() return MyArrayListValue( someVal = someVal, myPersonalData = myVal?.let { MyPersonalData(myVal = it) } ) } }
2. 注册适配器并解析JSON
创建Gson实例时注册自定义的TypeAdapter,之后用该实例完成解析:
// 注册自定义适配器 val gson = GsonBuilder() .registerTypeAdapter(MyArrayListValue::class.java, MyArrayListValueAdapter()) .create() // 原有解析流程不变,替换为自定义Gson实例 val jsonData = JsonParser.parseString( javaClass.getResourceAsStream(myJsonFile)!!.reader().readText() ).asJsonObject.get("data") val myParsedData = gson.fromJson(jsonData, MyDataClass::class.java)
通过这种方式,JSON中的myVal会被正确映射到MyArrayListValue.myPersonalData.myVal,无需修改原有JSON或数据类结构。
内容的提问来源于stack exchange,提问作者SilleBille
相关产品推荐
相关产品推荐

