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

如何用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 23:20:04