需求
这个需求很简单,需要将一个json object,转为一个Map<String, Any>类型,当然这个json object保证key是string类型。
func convert(json: JsonObject): Map<String, Any>
实现
目前有两种实现方式。 方法一:
fun convertLoop(jsonObject: JsonObject): Map<String, Any> {
val data = mutableMapOf<String, Any>()
for (key in jsonObject.keySet()) {
data[key] = jsonObject[key]
}
return data
}
方法二:
fun convertGson(jsonObject: JsonObject): Map<String, Any> {
val mapTypeToken = object : TypeToken<Map<String, Any>>() {}.type
return GsonBuilder().create().fromJson<Map<String, Any>>(jsonObject, mapTypeToken)
}
看上去方法二相对于方法一更加简洁,不需要遍历,只需要执行Gson自带的方法,但结果怎么样呢?
测试
val jsonObject = JsonObject()
jsonObject.addProperty("name", "zhang")
jsonObject.addProperty("isBoy", true)
jsonObject.addProperty("age", 20)
jsonObject.addProperty("weight", 70.1)
jsonObject.addProperty("timeStamp", System.currentTimeMillis())
Log.e("loopResult", convertLoop(jsonObject).toString())
Log.e("gsonResult", convertGson(jsonObject).toString())
E/loopResult: {name="zhang", isBoy=true, age=20, weight=70.1, timeStamp=1652421933173}
E/gsonResult: {name=zhang, isBoy=true, age=20.0, weight=70.1, timeStamp=1.652421933173E12}
可以看到在gson的转化下, 数字类型出了大问题,明明是age从20变成了20.0, timeStamp更是变成了double类型。 这到底是什么原因?
Gson源码中的坑
stackoverflow.com/questions/1… 可以从stackoverflow中找到相关的解释,原因是gson在解析时,默认将所有Json中的number解析成double类型
case NUMBER:
return in.nextDouble();
这个问题在gson 2.8.6的版本中也有出现。
解决方式
- 使用loop的方式获取数据,可能代码上不够优雅。
- 更新Gson到最新的2.9.0版本. 在这个版本中,google添加了ToNumberStrategy,其中默认的策略依然是转化为double,但可以设置为ToNumberPolicy.LONG_OR_DOUBLE.
fun convertGson(jsonObject: JsonObject): Map<String, Any> {
val mapTypeToken = object : TypeToken<Map<String, Any>>() {}.type
val gson = GsonBuilder().setNumberToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).setObjectToNumberStrategy(ToNumberPolicy.LONG_OR_DOUBLE).create()
return gson.fromJson<Map<String, Any>>(jsonObject, mapTypeToken)
}
在设定策略之后,现在输出就正常了