解決fastjson內存對象重複/循環引用json錯誤

什麼是重複/循環引用java

簡單說,重複引用就是一個集合/對象中的多個元素/屬性同時引用同一對象,循環引用就是集合/對象中的多個元素/屬性存在相互引用致使循環。spring

舉例說明json

  1. 重複引用編碼

    1. List<Object> list = new ArrayList<>();  
    2. Object obj = new Object();  
    3. list.add(obj);  
    4. list.add(obj);  

     

  2. 循環引用spa

    1. // 循環引用的特殊狀況,自引用  
    2. Map<String,Object> map = new HashMap<>();  
    3. map.put("map",map);  
    4. //  
    5. // map1引用了map2,而map2又引用map1,致使循環引用  
    6. Map<String,Object> map1 = new HashMap<>();  
    7. Map<String,Object> map2 = new HashMap<>();  
    8. map1.put("map",map2);  
    9. map2.put("map",map1);  

     

循環引用會觸發的問題

暫時不說重複引用,單說循環引用。
通常來講,存在循環引用問題的集合/對象在序列化時(好比Json化),若是不加以處理,會觸發StackOverflowError異常。對象

 

分析緣由:get

  1. 當序列化引擎解析map1時,它發現這個對象持有一個map2的引用,轉而去解析map2。解析map2時,發現他又持有map1的引用,又轉回map1。如此產生StackOverflowError異常。  

FastJson對重複/循環引用的處理

首先,fastjson做爲一款序列化引擎,不可避免的會遇到循環引用的問題,爲了不StackOverflowError異常,fastjson會對引用進行檢測。table

若是檢測到存在重複/循環引用的狀況,fastjson默認會以「引用標識」代替同一對象,而非繼續循環解析致使StackOverflowError。ast

以上文兩例說明,查看json化後的輸出object

  1. 重複引用 JSON.toJSONString(list)

  2. [  
  3.     {},  //obj的實體  
  4.     {  
  5.         "$ref": "$[0]"   //對obj的重複引用的處理  
  6.     }  
  7. ]  

 


     2.循環引用 JSON.toJSONString(map1)

 

  1. {  
  2. // map1的key:value對  
  3.     "map": {  
  4.          // map2的key:value對  
  5.         "map": {  
  6.              // 指向map1,對循環引用的處理  
  7.             "$ref": ".."  
  8.         }  
  9.     }  
  10. }  

引用標識說明:

「$ref」:」..」 上一級
「$ref」:」@」 當前對象,也就是自引用
「$ref」:」$」 根對象
「$ref」:」$.children.0」 基於路徑的引用,至關於root.getChildren().get(0)

關閉FastJson的引用檢測

1
JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);

FastJson提供了SerializerFeature.DisableCircularReferenceDetect這個序列化選項,用來關閉引用檢測。關閉引用檢測後,重複引用對象時就不會被$ref代替,可是在循環引用時也會致使StackOverflowError異常。

避免重複引用序列化時顯示$ref

  1. 在編碼時,使用新對象爲集合或對象賦值,而非使用同一對象
    不要在多處引用同一個對象,這能夠說是一種java編碼規範,須要時刻注意。
  2. 不要關閉FastJson的引用檢測來避免顯示$ref
    引用檢測是FastJson提供的一種避免運行時異常的優良機制,若是爲了不在重複引用時顯示$ref而關閉它,會有很大可能致使循環引用時發生StackOverflowError異常。這也是FastJson默認開啓引用檢測的緣由。

避免重複/循環引用的正確姿式

  1. 重複引用

    1
    2
    3
    4
    5
    6
    7
    8
    List<Object> list = new ArrayList<>();
    Object obj = new Object();
    list.add(obj);
    // 建立新的對象
    Object newObj = new Object();
    // 使用org.springframework.beans.BeansUtils複製屬性值
    BeansUtils.copy(obj, newObj);
    list.add(obj);
  2. 循環引用 循環引用這種邏輯自己就不合理,須要在編碼時注意避免,這是邏輯錯誤而非編碼技巧。

相關文章
相關標籤/搜索