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;
                    }
                }
        }
    }

这样就将小数类型的数据自动改成了字符串类型。我们只需在自己项目中定义相同的包,相同的类,并复制相同的代码,然后进行修改即可。这样会将源码中的这个类进行覆盖。

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

敲代码的小小酥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值