场景如下: web端传递一个JSON 至服务端,服务端进行解析并处理时,出现了一个诡异的现象。
-
在我们日常的项目中,为了解决浏览器端处理
long
类型参数时,存在精度都丢失的问题,我们通常会将long
转为string
再传递给前端 -
正常的情况下,当我们向服务器发起请求时,我们服务端使用 DTO接收参数,spring 会自动做对象转换,此时也不会出现什么异常。
-
问题是,当你觉得参数不多,定义个DTO又麻烦,干脆用 String 接收参数,再自行转换为对象,进行数据取值时,问题就来了。
如:前端请求参数为:
{
"id": "445065833448300548",
"note": "不合格!"
}
当你使用 net.sf.json.JSONObject
进行处理时,你会发现…
String content = "{ \"id\": \"445065833448300548\", \"note\": \"不合格!\" }";
net.sf.json.JSONObject obj = net.sf.json.JSONObject.fromObject(content);
Long id = obj.getLong("id");
System.out.println(id);
System.out.println(id.compareTo(445065833448300548L) == 0);
啥? 啥情况?
你没看错,输出的结果,根本不是同一个值
究其根本原因,是
net.sf.json.JSONObject
的getLong()
方法在处理数据时,如果参数类型不为Number
,那它就先使用Double.parseDouble()
方法,先将值转为double
类型,再强制转为long
类型。在这个double
转为long
的过程中,精度丢失了。(至于精度丢失的原因,有兴趣的小伙伴可以自行Google深度了解一下!)
package net.sf.json;
public final class JSONObject extends AbstractJSON implements JSON, Map, Comparable {
// ....
public long getLong(String key) {
this.verifyIsNull();
Object o = this.get(key);
if (o != null) {
return o instanceof Number ? ((Number)o).longValue() : (long)this.getDouble(key);
} else {
throw new JSONException("JSONObject[" + JSONUtils.quote(key) + "] is not a number.");
}
}
// ....
public double getDouble(String key) {
this.verifyIsNull();
Object o = this.get(key);
if (o != null) {
try {
return o instanceof Number ? ((Number)o).doubleValue() : Double.parseDouble((String)o);
} catch (Exception var4) {
throw new JSONException("JSONObject[" + JSONUtils.quote(key) + "] is not a number.");
}
} else {
throw new JSONException("JSONObject[" + JSONUtils.quote(key) + "] is not a number.");
}
}
}
- 那
fastjson
或者Gson
也存在这个问题吗?
public static void main(String[] args) {
String content = "{ \"id\": \"445065833448300548\", \"note\": \"不合格!\" }";
System.out.println("------------------ net.sf.json ------------------");
net.sf.json.JSONObject obj = net.sf.json.JSONObject.fromObject(content);
Long id = obj.getLong("id");
System.out.println(id);
System.out.println(id.compareTo(445065833448300548L) == 0);
System.out.println("------------------ com.alibaba.fastjson ------------------");
com.alibaba.fastjson.JSONObject obj2 = com.alibaba.fastjson.JSONObject.parseObject(content);
Long id2 = obj2.getLong("id");
System.out.println(id2);
System.out.println(id2.compareTo(445065833448300548L) == 0);
System.out.println("------------------ com.google.gson ------------------");
com.google.gson.JsonObject obj3 = new com.google.gson.JsonParser().parse(content).getAsJsonObject();
Long id3 = obj3.get("id").getAsLong();
System.out.println(id3);
System.out.println(id3.compareTo(445065833448300548L) == 0);
}
经测试,
fastjson
跟Gson
都正常,妥妥的!