【发布时间】:2019-04-26 00:12:47
【问题描述】:
考虑以下代码:
val myarray = arrayListOf("hello", "world")
println(myarray)
println(myarray::class.java.name)
val arrayString = mapper.writeValueAsString(myarray)
println(arrayString)
println(arrayString::class.java.name)
val myMap = HashMap<String, String?>()
myMap["key"] = JsonPath.read<String>(arrayString, "$")
println(myMap["key"])
println(myMap["key"]!!::class.java.name)
此代码创建一个包含值“hello”和“world”的 ArrayList,将列表转换为 json 字符串,读取 json 的根元素(这是一个告诉返回字符串的通用函数)并将其存储在哈希映射
此代码编译并运行没有错误,并产生以下输出:
[hello, world]
java.util.ArrayList
["hello", "world"]
java.lang.String
["hello","world"]
net.minidev.json.JSONArray
myMap["key"] 如何返回JSONArray? (回想一下,myMap 被声明为<String, String?>)
Kotlin 在编译时检查了它的类型,但是因为泛型函数 JsonPath.read 被告知返回 String,所以编译正常。
JsonPath.read 然后似乎违反了它的合同并返回JSONArray 而不是String。 Kotlin 似乎没有对此进行类型检查,并允许将 JSONArray 存储在 Map<String, String?> 中。
除非我尝试将myMap["key"] 用作String,否则不会产生错误
注意
这个问题可以通过将读取json的行改为:
myMap["key"] = ObjectMapper().writeValueAsString(JsonPath.read<String>(arrayString, "$"))
编辑
不使用json疯狂的代码示例:
fun <T> myFun(): T {
return 7 as T
}
fun test() {
val map = HashMap<String, String?>()
map["key"] = myFun<String>()
println(map["key"])
println(map["key"]!!::class.java.name)
}
returns:
7
java.lang.Integer
【问题讨论】:
-
您有一个字符串列表并试图将其解析为字符串。 kotlin 或 java 应该如何处理这个问题?引用自docs:
When using JsonPath in java its important to know what type you expect in your result. -
@aweson 我希望 kotlin 说“嘿,你只是试图将 JSONArray 存储到需要字符串的地图中”或 JsonPath 说“嘿,你请求了一个字符串,但这不是一个字符串”。在我发现这一点的系统中,用户可以传入一组路径并期望返回 key=path 和 value=json 字符串的映射。我不知道路径上的类型。我在这里感兴趣的问题不是我的错误代码,而是 kotlin 允许将非字符串类型成功存储在字符串映射中。
-
JsonPath 承诺会返回 String。它撒谎了,因为它无法访问您请求的实际类型(类型擦除),而不是检查结果是否为
String,它只是返回一个对象并说“您要求 T - 这是一些东西我找到了,希望它是 T"。 -
我对 JsonPath 撒谎没意见(尽管我觉得不应该这样做),但我觉得当我们使用 map 的 put 方法时,应该定义类型地图就像“等一下。那不是字符串”。使用泛型,我基本上可以滥用 map
并将其视为 map -
"等一下。那不是字符串" - 如果 Map 能够执行此检查,为什么
JsonPath无法检查它将返回的对象的类型?这就是泛型的实现方式。您在运行时无权访问泛型类型。