Json-lib工具包解析小数自动四舍五入导致小数值丢失问题解决
Posted 敲代码的小小酥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Json-lib工具包解析小数自动四舍五入导致小数值丢失问题解决相关的知识,希望对你有一定的参考价值。
背景
项目中采用了json-lib作为json解析转化工具。在转化经纬度信息的时候,把小数点位数做了四舍五入,导致经纬度定位不准。换fastjson或Gson的话代码还得改动,且fastjson和Gson对于格式不太标准的json数据格式,会解析失败,如{a=b,c=d}这种非标准json的数据,json-lib会解析成功,而fastjson和Gson不会。所以不想改动json-lib。
解决
最简单的解决方式是将经纬度值改成字符串类型,这样就不会丢失精度了。但是尴尬的是经纬度信息,是从其他接口对接过来的。无法修改它的数值类型。所以,只能在json-lib解析属性值的时候,将数值改成字符串类型。所以,要找json-lib源码中哪里解析的属性值,然后修改其源码。
先说解决方案:
json-lib中解析数据值的类是net.sf.json.util.JSONTokener类,里面的nextValue方法如下:
public Object nextValue(JsonConfig jsonConfig) {
char c = this.nextClean();
switch(c) {
case '"':
case '\\'':
return this.nextString(c);
case '[':
this.back();
return JSONArray.fromObject(this, jsonConfig);
case '{':
this.back();
return JSONObject.fromObject(this, jsonConfig);
default:
StringBuffer sb = new StringBuffer();
char b;
for(b = c; c >= ' ' && ",:]}/\\\\\\"[{;=#".indexOf(c) < 0; c = this.next()) {
sb.append(c);
}
this.back();
String s = sb.toString().trim();
if (s.equals("")) {
throw this.syntaxError("Missing value.");
} else if (s.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (s.equalsIgnoreCase("false")) {
return Boolean.FALSE;
} else if (s.equals("null") || jsonConfig.isjavascriptCompliant() && s.equals("undefined")) {
return JSONNull.getInstance();
} else if ((b < '0' || b > '9') && b != '.' && b != '-' && b != '+') {
if (!JSONUtils.isFunctionHeader(s) && !JSONUtils.isFunction(s)) {
switch(this.peek()) {
case ',':
case '[':
case ']':
case '{':
case '}':
throw new JSONException("Unquotted string '" + s + "'");
default:
return s;
}
} else {
return s;
}
} else {
if (b == '0') {
if (s.length() <= 2 || s.charAt(1) != 'x' && s.charAt(1) != 'X') {
try {
return new Integer(Integer.parseInt(s, 8));
} catch (Exception var8) {
}
} else {
try {
return new Integer(Integer.parseInt(s.substring(2), 16));
} catch (Exception var9) {
}
}
}
try {
return NumberUtils.createNumber(s);
} catch (Exception var7) {
return s;
}
}
}
}
可以看到,小数类型的数据,最终走到了NumberUtils.createNumber(s);方法里,这个方法,对小数位数进行了四舍五入。所以,我们只需把它改成直接返回String类型的即可,不再使用这个方法。
修改后的代码如下:
public Object nextValue(JsonConfig jsonConfig) {
char c = this.nextClean();
switch(c) {
case '"':
case '\\'':
return this.nextString(c);
case '[':
this.back();
return JSONArray.fromObject(this, jsonConfig);
case '{':
this.back();
return JSONObject.fromObject(this, jsonConfig);
default:
StringBuffer sb = new StringBuffer();
char b;
for(b = c; c >= ' ' && ",:]}/\\\\\\"[{;=#".indexOf(c) < 0; c = this.next()) {
sb.append(c);
}
this.back();
String s = sb.toString().trim();
if (s.equals("")) {
throw this.syntaxError("Missing value.");
} else if (s.equalsIgnoreCase("true")) {
return Boolean.TRUE;
} else if (s.equalsIgnoreCase("false")) {
return Boolean.FALSE;
} else if (s.equals("null") || jsonConfig.isJavascriptCompliant() && s.equals("undefined")) {
return JSONNull.getInstance();
} else if ((b < '0' || b > '9') && b != '.' && b != '-' && b != '+') {
if (!JSONUtils.isFunctionHeader(s) && !JSONUtils.isFunction(s)) {
switch(this.peek()) {
case ',':
case '[':
case ']':
case '{':
case '}':
throw new JSONException("Unquotted string '" + s + "'");
default:
return s;
}
} else {
return s;
}
} else {
if (b == '0') {
if (s.length() <= 2 || s.charAt(1) != 'x' && s.charAt(1) != 'X') {
try {
return new Integer(Integer.parseInt(s, 8));
} catch (Exception var8) {
}
} else {
try {
return new Integer(Integer.parseInt(s.substring(2), 16));
} catch (Exception var9) {
}
}
}
try {
return s;
} catch (Exception var7) {
return s;
}
}
}
}
这样就将小数类型的数据自动改成了字符串类型。我们只需在自己项目中定义相同的包,相同的类,并复制相同的代码,然后进行修改即可。这样会将源码中的这个类进行覆盖。
以上是关于Json-lib工具包解析小数自动四舍五入导致小数值丢失问题解决的主要内容,如果未能解决你的问题,请参考以下文章
SQL中decimal和numeric为啥会自动四舍五入啊?我是想保留有小数的怎么办?
JS 保留2位小数 四舍五入(小数点后面不足2位,自动用0补齐)