天天看點

fastjson 處理 double 的精度問題

項目中使用 fastjson 來處理 json 格式,目前使用的版本為1.1.37。在和其它系統互動時,将一個json串傳給了對方,原值為5.0,json 處理後格式為:{"dou", 5}; 結果對方處理該串報錯了, 原因是他将串整理轉成 Map ,在取值時強制轉為了 Double ,因為拿到的值轉化是 Integer 類型,強轉肯定異常了。 簡單的做法應該通過 Double.valueOf(value)  進行處理。但無奈合作方不願意處理。 于是測試了下fastjson處理這個串時,通過以下做處理, 輸出的結果為 {"dou", 5}。

JSONObject jsonObject = new JSONObject();
Double dou = new Double(5.0);
jsonObject.put("dou", dou);
System.out.println(JSON.toJSONString(jsonObject));      

想要輸出{"dou",5.0} 怎麼辦, 跟蹤了下源碼,發現在 DoubleSerializer 的 write 方法中,判斷了結尾如果是.0 就截掉了。

doubleText = Double.toString(doubleValue);
if(doubleText.endsWith(".0")) {
    doubleText = doubleText.substring(0, doubleText.length() - 2);
}      

那想要的格式怎麼辦,可以通過自定義 filter 方式實作,:

ValueFilter filter = new ValueFilter() {
            @Override
            public Object process(Object object, String name, Object value) {
                if(value instanceof BigDecimal || value instanceof Double || value instanceof Float){
                    return new BigDecimal(value.toString());
                }
                return value;
            }
        };

String s  = JSON.toJSONString(jsonObject, filter, new SerializerFeature[0]);      

以上可以完美解決。後來想有沒有跟好的方法呢。 于是網上搜尋了一下,大多數都是這種做法,并且有人認為這是一個bug,于是突然想有沒有可能 wenshao 會處理一下,于是在 github 找到 fastjson 的最新版本 1.2.23。 先修改 pom 檔案,然後運作。發現即使不處理也能輸出了 {"dou",5.0} 。 于是 debug 進去原來對 DoubleSerializer 進行了重寫,并在 write 方法中原來處理格式的地方修改為如下:

if (decimalFormat == null) {
    out.writeDouble(doubleValue, true);
} else {
    String doubleText = decimalFormat.format(doubleValue);
    out.write(doubleText);
}

//out SerializeWriter
String doubleText = Double.toString(doubleValue);
if (isEnabled(SerializerFeature.WriteNullNumberAsZero) && doubleText.endsWith(".0")) {
    doubleText = doubleText.substring(0, doubleText.length() - 2);
}      

即,以上粉色代碼調用 SerializeWriter 的writeDouble 方法, 看綠色部分。 同時判斷了 SerializerFeature.WriteNullNumberAsZero 和 結尾是否為 .0

就是通過這個解決了 double 精度的正常輸出。  在使用 1.2.23時如果想輸出{"dou", 5}, 可以通過設定 SerializerFeature.WriteNullNumberAsZero 實作。

System.out.println(JSON.toJSONString(jsonObject, SerializerFeature.WriteNullNumberAsZero));      

啰嗦了這麼,希望通過更新版本解決同樣遇到這樣問題的小夥伴。