为什么Gson允许普通的数组声明,然后在Map中访问它时抛出ClassCastException?

puruo6ea  于 2022-11-06  发布在  其他
关注(0)|答案(1)|浏览(146)

当使用Gson将JSONMap转换为Kotlin/JavaMap,并且JSON值包含"[]"形式的数组时,如果声明并访问Array<T>,则会出现ClassCastException错误。(Array<T>等效于Java数组T[]):
应用程序/构建.gradle:

dependencies {
   ...
   implementation 'com.google.code.gson:gson:2.8.6'
}

jsonConverter.kt(使用this guide):

@Throws(JsonSyntaxException::class)
fun gsonMapTest() {
    val jsonInput = """
        {"keyOne":[],"keyTwo":["valueA"],"keyThree":[]}
    """.trimIndent()

    // Guidance: https://www.baeldung.com/gson-json-to-map
    val jsonMap1 = Gson().fromJson<LinkedTreeMap<String, Array<String>>>(jsonInput, MutableMap::class.java)
    val jsonMap2: Map<*,*> = Gson().fromJson(jsonInput, Map::class.java) // MutableMap can also be used

    // These work fine
    val firstKeyInMap1: String = jsonMap1.keys.first() // returns String
    val firstKeyInMap2 = jsonMap2.keys.first() // returns String

    // Errors here: "java.lang.ClassCastException: java.util.ArrayList cannot be cast to [Ljava.lang.String;"
    val firstValueInMap1: Array<String> = jsonMap1.values.first()
    val firstValueInMap2: Array<String> = jsonMap2.values.first() as Array<String>
}

此错误发生在运行时:

java.lang.ClassCastException: java.util.ArrayList cannot be cast to [Ljava.lang.String;

但是Map对象被允许创建,没有任何警告或错误,只有当访问Map值时才会发生错误。
从错误消息中,我最初认为对jsonMap1.values.first()的调用是试图将空数组转换为String。

如果代码示例中的声明从Array<String>更改为ArrayList<String>,则一切正常。

"我的问题是"

  • Gson允许Array<T>声明,但在访问项时会导致错误,这是正常的行为吗?
  • 有没有办法显示警告或编译错误,说明应该使用ArrayList<String>而不是Array<String>

我检查了Gson的Github问题。我没有发现这个问题,但我发现了一些稍微相似的问题:

更新:也许这是同样的问题?:Java gson, ClassCastException on decoding to Map<String,String[]>

evrscar2

evrscar21#

正如用户 fluffy 在他/她的评论中提到的,除了泛型描述之外,还必须使用TypeToken来反序列化参数化泛型类型。但是,ArrayList<String>似乎不需要这样做:

@Test
@Throws(JsonSyntaxException::class)
fun gsonMapTest() {
    val jsonInput = """
    {"keyOne":[],"keyTwo":["valueA"],"keyThree":[]}
    """.trimIndent()

    // Guidance: https://www.baeldung.com/gson-json-to-map
    val jsonMap1 = Gson().fromJson<LinkedTreeMap<String, ArrayList<String>>>(jsonInput, MutableMap::class.java)

    val listType = object : TypeToken<LinkedTreeMap<String, Array<String>>>() {}.type
    val jsonMap2: Map<*,*> = Gson().fromJson(jsonInput, listType) // MutableMap can also be used

    // These work fine
    val firstKeyInMap1: String = jsonMap1.keys.first() // returns String "keyOne"
    val firstKeyInMap2 = jsonMap2.keys.first() // returns String "keyOne"

    // No longer errors here
    val firstValueInMap1: ArrayList<String> = jsonMap1.values.first() // returns empty list
    val firstValueInMap2: Array<String> = jsonMap2.values.first() as Array<String> // returns empty array
}

相关问题