如何将 json 映射到具有嵌套包装器子级的数据类?

问题描述 投票:0回答:1

我正在尝试为 GraphQL 解析器编写单元测试。我有这个 JSON 文件结构:

{
     "data": {
         "myVar": {
              "myArray": [{
                         "someVal": "someStr1",
                         "myVal": "myStr1", 
                   }, {
                         "someVal": "someStr2",
                         "myVal": "myStr2"
                   }
               ]
         }
     }
}

这是我的 MyDataClass.kt:

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( // The wrapper class around `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
。即,
myParsedData.myVar.myArray[x].myPersonalData.myVal
设置为
null

请注意,我不想更改 JSON 结构或数据类结构,因为它是提供给我的。相反,我想要一种将 JSON 正确映射到数据类的方法。有没有更好的方法来做到这一点,而无需手动沿着树走下去并创建各个子节点的新实例?

json kotlin gson
1个回答
0
投票

您可以使用带有 Gson 的自定义反序列化器来处理嵌套属性的映射逻辑。为

MyArrayListValue
编写一个自定义反序列化器,从 JSON 结构中提取
myVal
字段并将其设置为
myPersonalData.myVal
,您可以按照以下代码操作:

import com.google.gson.*
import java.lang.reflect.Type

data class MyDataClass(
    val myVar: MyBaseVar? = null
)

data class MyBaseVar(
    val myArray: List<MyArrayListValue>? = null
)

data class MyArrayListValue(
    val someVal: String? = null,
    val myPersonalData: MyPersonalData? = null
)

data class MyPersonalData(
    val myVal: String? = null
)

class MyArrayListValueDeserializer : JsonDeserializer<MyArrayListValue> {
    override fun deserialize(
        json: JsonElement,
        typeOfT: Type?,
        context: JsonDeserializationContext?
    ): MyArrayListValue {
        val jsonObject = json.asJsonObject
        val someVal = jsonObject.get("someVal")?.asString
        val myVal = jsonObject.get("myVal")?.asString

        val myPersonalData = MyPersonalData(myVal)

        return MyArrayListValue(someVal, myPersonalData)
    }
}

fun main() {
    val gson = GsonBuilder()
        .registerTypeAdapter(MyArrayListValue::class.java, MyArrayListValueDeserializer())
        .create()

    val myJsonFile = "path/to/your/json/file.json"
    val jsonData = JsonParser.parseString(
        javaClass.getResourceAsStream(myJsonFile)!!.reader().readText()
    ).asJsonObject.get("data")

    val myParsedData = gson.fromJson(jsonData, MyDataClass::class.java)

    // Now myParsedData should have the correct mapping for myPersonalData.myVal
    println(myParsedData)
}

上面的代码,

MyArrayListValueDeserializer
类扩展了
JsonDeserializer<MyArrayListValue>
并重写了
deserialize
方法。在此方法中,它手动从 JSON 中提取值并使用
MyArrayListValue
的正确映射构造
myPersonalData.myVal
对象。然后在创建 Gson 实例时使用
registerTypeAdapter
向 Gson 注册自定义反序列化器。

希望有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.