fastjson字串轉JSON的$ref問題

lichlaughing發表於2022-01-15

先說結論:

fastjson在把物件轉換成字串的時候,如果遇到相同的物件的時候,預設開啟引用檢測將相同的物件寫成引用的形式。

官網文件:https://github.com/alibaba/fastjson/wiki

問題出現的背景:

在開發過程中,使用了第三方的拓撲圖元件。元件生成圖形的json字串在利用 fastjson 轉換成 JSON 物件的時候報錯如下所示:

Exception in thread "main" com.alibaba.fastjson.JSONException: illegal ref, int

後來定位到如下的字串解析的時候會出錯:

public class test {
    public static void main(String[] args) {
        String str1 = "{\"$position\":{\"$ref\":21}}";
        String str2 = "{\"position\":{\"ref\":21}}";
        JSONObject json = JSONObject.parseObject(str1);
    }
}

解析str2沒問題,解析str1報錯 Exception in thread "main" com.alibaba.fastjson.JSONException: illegal ref, int

剛開始判斷是$符號是特殊符號導致,所以去掉後解析str2沒問題。

後來又測試下去掉第一個$

String str1 = "{\"position\":{\"$ref\":21}}";

還是報錯:Exception in thread "main" com.alibaba.fastjson.JSONException: illegal ref, int

那麼問題出現在第二個$ref上了。那麼懷疑$ref 就好像保留欄位一樣,不能使用,於是修改為

String str1 = "{\"position\":{\"$reff\":21}}";

那麼呼叫JSONObject.parseObject(str1);果然就正常了。

查閱官網資料:fastjson支援迴圈引用,並且是預設開啟的。

如果有相同的物件,那麼 fastjson 會預設開啟引用模式。

語法 描述
{"$ref":"$"} 引用根物件
{"$ref":"@"} 引用自己
{"$ref":".."} 引用父物件
{"$ref":"../.."} 引用父物件的父物件
{"$ref":"$.members[0].reportTo"} 基於路徑的引用

官網還給出了說明:

當序列化後的JSON傳輸到瀏覽器或者其他語言中,這些json解析器不支援迴圈引用,從而導致資料丟失。你可以關閉fastjson的迴圈引用支援。關閉引用檢測,還能夠提升序列化時的效能。

全域性配置關閉

  JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

非全域性關閉

  JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);

綜上,我們的字串中包括"$ref",fastjson 認為這是引用模式,但是引用的值又是不正確的,導致出錯。

解決方式上面說了兩種,一種全域性,一種非全域性的。

我們採用非全域性的,那麼下面的程式碼就是正確✅的了

public class test {
    public static void main(String[] args) {
        String str1 = "{\"$position\":{\"$reff\":21}}";
        JSONObject json = JSONObject.parseObject(str1, Feature.DisableCircularReferenceDetect);
        System.out.println(json);
    }
}
結果:
{"$position":{"$reff":21}}

相關文章