問題描述
在一次開發過程當中遇到的一個關於FastJson的問題,我獲取到的數據對象是一種無規則的json字符串,需要轉換爲JsonObject對象後存入到MongDB裏面。但是在數據提交到MongoDB時發現,原本提交的Double類型保存到MongoDB的時候發現這個數據類型變成了String類型。因爲在mongo中使用了2dsphere,也出現了Can’t extract geo keys錯誤信息。
查詢問題
測試代碼
class TestEntity {
private Double doubleVal;
private Float floatVal;
private String name;
public Double getDoubleVal() {
return doubleVal;
}
public void setDoubleVal(Double doubleVal) {
this.doubleVal = doubleVal;
}
public Float getFloatVal() {
return floatVal;
}
public void setFloatVal(Float floatVal) {
this.floatVal = floatVal;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class JSONTest {
public static void main(String[] args) {
TestEntity testEntity = new TestEntity();
testEntity.setDoubleVal(123.456001);
testEntity.setFloatVal(123.45512F);
testEntity.setName("測試FastJSON");
String str = JSON.toJSON(testEntity).toString();
JSONObject JB = JSON.parseObject(str);
System.out.println("***** Test Start ******");
System.out.println("doubleVal = " + JB.get("doubleVal"));
System.out.println("floatVal = " + JB.get("floatVal"));
System.out.println("name = " + JB.get("name"));
}
}
開始debug代碼查找具體的問題出現在哪裏。經過的debug發現在使用alibaba的fastJson轉換的時候原數據裏面的Double類型被轉換成了BigDecimal。如下圖所示
然後開始查看所調用的API文檔,最終定位到問題所在
在JSON類裏面的靜態代碼塊
static {
int features = 0;
int features = features | Feature.AutoCloseSource.getMask();
features |= Feature.InternFieldNames.getMask();
features |= Feature.UseBigDecimal.getMask();
features |= Feature.AllowUnQuotedFieldNames.getMask();
features |= Feature.AllowSingleQuotes.getMask();
features |= Feature.AllowArbitraryCommas.getMask();
features |= Feature.SortFeidFastMatch.getMask();
features |= Feature.IgnoreNotMatch.getMask();
DEFAULT_PARSER_FEATURE = features;
features = 0;
features = features | SerializerFeature.QuoteFieldNames.getMask();
features |= SerializerFeature.SkipTransientField.getMask();
features |= SerializerFeature.WriteEnumUsingName.getMask();
features |= SerializerFeature.SortField.getMask();
String featuresProperty = IOUtils.getStringProperty("fastjson.serializerFeatures.MapSortField");
int mask = SerializerFeature.MapSortField.getMask();
if("true".equals(featuresProperty)) {
features |= mask;
} else if("false".equals(featuresProperty)) {
features &= ~mask;
}
DEFAULT_GENERATE_FEATURE = features;
bytesLocal = new ThreadLocal();
charsLocal = new ThreadLocal();
}
在JSON類裏面的靜態代碼塊的第五行發現了 features |= Feature.UseBigDecimal.getMask();
通過對Feature類的查詢發現UseBigDecimal這個設置是用來使用BigDecimal來裝載數字的,否則使用Double。但是在JSON類中的靜態代碼塊中默認設置爲了True。
如何解決
出現問題就開始各種BD、Google問題。最終在全球最大的男性交流平臺的官方倉庫的Wiki中找到了答案
鏈接: github deserialize_disable_bigdecimal_cn.
按照Wiki的方法進行了下修改,解決了問題。
TestEntity testEntity = new TestEntity();
testEntity.setDoubleVal(123.456001);
testEntity.setFloatVal(123.45512F);
testEntity.setName("測試FastJSON");
int disableDecimalFeature = JSON.DEFAULT_PARSER_FEATURE & ~Feature.UseBigDecimal.getMask();
String str = JSON.toJSON(testEntity).toString();
//JSONObject JB = JSON.parseObject(str);
JSONObject JB = JSON.parseObject(str,JSONObject.class,disableDecimalFeature);
System.out.println("***** Test Start ******");
System.out.println("doubleVal = " + JB.get("doubleVal"));
System.out.println("floatVal = " + JB.get("floatVal"));
System.out.println("name = " + JB.get("name"));
不過Float類型還是變成了Double類型,這個問題還沒有解決掉。
說實話還有一個坑就是在使用FastJson的時候有時候序列化以後變成無序的狀態,這個時候就要使用 Feature.OrderedField 這個特性,因爲默認是未開啓的
JSONObject JB = JSON.parseObject(str,JSONObject.class,disableDecimalFeature,Feature.OrderedField);
以上解決掉了所有問題了,感謝提供幫助的羣裏的小夥伴。