【FastJSON】解決FastJson中“$ref 迴圈引用”的問題
https://blog.csdn.net/qq_35873847/article/details/78850528
【需求與環境描述】
0、開發環境
SSH,EasyUI,MySQL
1、需求要求:
(1)首先獲取所有的貸款訂單資料,即List <LoanOrder>。
(2)然後從單個貸款訂單實體LoanOrder去訪問貸款人實體Loaner的資訊。
2、實體之間的關係描述
(1)LoanOrder實體與Loaner實體是雙向的多對一和一對多關係。
(2)LoanOrder是“多方”,其中的關係屬性為“private Loaner loaner”。
(3)Loaner是“一方”,其中的關係屬性為“Set<LoanOrder> orders”。
3、程式碼示例
(1) 貸款訂單LoanOrder程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
(2) Loaner方程式碼
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
【障礙再現】
1、需求01:
首先獲取所有的貸款訂單資料,即List <LoanOrder>,發現貸款人“張三”有兩個訂單。
2、需求02:
然後,依次在第一個和第二個貸款訂單中點選“張三”,從而去訪問“名字叫做‘張三’”貸款人實體Loaner的資訊。
結果,第一個訂單可以顯示貸款人的資料,但是在第二個訂單資料中,不能獲取到“loaner(貸款人)”的資料,並且loaner中提示“$ref”。
經過兩次點選後,伺服器後臺傳送到前臺頁面上的JSON資料如下所示:
【解決方案】
第一步:禁用FastJson的“迴圈引用檢測”特性。
1、核心程式碼
2、作用
決定了生成的“多個”JSON物件中,是否載入被引用的同一個物件的資料。
在此,決定了生成的“多個”貸款訂單JSON物件中,是否載入被引用的同一個貸款人JSON物件的資料。
3、開啟和關閉FastJson的“迴圈引用檢測”特性的對比
當從伺服器端傳來的多個LoanOrder物件通過FASTJSON被序列化到“前端”後,會被瀏覽器解析成“DOM”物件。
(1) 當開啟FastJson的“迴圈引用檢測”特性時:
1)對於第一個LoanOrder 01,fastjson會完全解析並載入它的所有資料,包括它所關聯的Loaner貸款人資訊,如下圖所示。
2) 對於第二個LoanOrder 02,fastjson僅僅解析並載入其貸款訂單部分的資料,對於“$ref”所指向的 Loaner貸款人的資料,fastjson會因為“開啟了fastJson的‘迴圈引用檢測’機制”而不去載入該貸款人資料。
當載入第二個貸款訂單資料時,fastjson檢測到已經在第一個訂單LoanOrder 01中載入了“貸款人Loaner”的資料,fastjson會因為“開啟了‘迴圈引用檢測’機制”而不去再次載入該貸款人資料,而僅僅將一個指向第一個貸款訂單LoanOrder01中“貸款人”的引用賦值給第二個貸款訂單中的貸款人的位置。
因此,在生成的第二個貸款訂單的JSON串中,對於貸款人資訊,僅僅只有一個“$ref”。
而jQuery這個前端技術又無法解析該引用,因此,就無法讀取貸款人的資料,如下圖所示。
第二步:禁止Loaner物件獲取Set<LoanOrder>的資料。
方法一:將原來的“雙向關係”修改為“單向關係”
1、原來:LoanOrder與Loaner之間是雙向關係。
2、修改後:只能從LoanOrder訪問Loaner,從Loaner無法訪問到LoanOrder。
3、具體方法01
重要前提:不刪除Loaner中的“Set<LoanOrder> orders”屬性。
注意,若在採用註解對映實體類的方式中,沒有使用“@Transient”註解,則資料庫會報錯。
4、具體方法02
直接刪除“Set<LoanOrder> orders”屬性極其相關的setter()和getter()方法。
方法二:不修改關係的前提下,禁止序列化
在不修改LoanOrder和Loaner雙向關係的情況下,Loaner物件中的Set<LoanOrder>集合完成資料的載入,當其向前端Browser傳遞JSON資料時,禁止序列化Set<LoanOrder>集合。
具體方法:
設定註解“@JSONField(serialize = false)”。
說明:
A.“@JSONField”是fastjson提供的註解標籤,其作用為控制其所標註的屬性“能否被序列化”。
B.在此其作用為:禁止"loanOrders"這個Set集合被序列化。
具體如下圖所示。
【解決後的效果】
讀者如要轉載,請標明出處和作者名,謝謝。
地址01:http://space.itpub.net/25851087
地址02:http://www.cnblogs.com/zjrodger
作者名:zjrodger
問題描述:
今天在做後臺傳資料到前端解析的時候遇到了這個問題。背景介紹下:後臺傳過去json資料是用阿里的fastjson轉換的,呼叫的是這個方法[java] view plain copy
- String s = JSON.toJSONStringWithDateFormat(o,dateformat,SerializerFeature.WriteDateUseDateFormat);
- ServletActionContext.getResponse().getWriter().write(s);
其中dataformat是格式化時間資料的。傳過去的是一個PageBean物件,該物件繼承了Page物件,Page裡面包含list,pageNo,pageSize。前臺在通過data.list準備取出list迴圈做點事情的時候,發現全是undefined,通過console.log(data.list),發現這個資料竟然是這個東西$ref: "$.list[0]"。百度搜了下,這裡就是迴圈引用造成的。
問題分析:
迴圈引用:當一個物件包含另一個物件時,fastjson就會把該物件解析成引用。引用是通過$ref標示的,下面介紹一些引用的描述
- "$ref":".." 上一級
- "$ref":"@" 當前物件,也就是自引用
- "$ref":"$" 根物件
- "$ref":"$.children.0" 基於路徑的引用,相當於 root.getChildren().get(0)
解決方案:
fastjson提供了多種json轉換方案,有興趣的同學可以自己看看原始碼,這裡我們可以採用禁止迴圈引用的方案:
[java] view plain copy
- String s = JSON.toJSONStringWithDateFormat(0,"yyyy-MM-dd HH:mm:ss",SerializerFeature.DisableCircularReferenceDetect);
其中:SerializerFeature.DisableCircularReferenceDetect就是禁止迴圈引用的方案,我們可以通過列舉類SerializerFeature來檢視到底有多少種方式:
[java] view plain copy
- public enum SerializerFeature {
- QuoteFieldNames,
- UseSingleQuotes,
- WriteMapNullValue,
- WriteEnumUsingToString,
- UseISO8601DateFormat,
- /**
- * @since 1.1
- */
- WriteNullListAsEmpty,
- /**
- * @since 1.1
- */
- WriteNullStringAsEmpty,
- /**
- * @since 1.1
- */
- WriteNullNumberAsZero,
- /**
- * @since 1.1
- */
- WriteNullBooleanAsFalse,
- /**
- * @since 1.1
- */
- SkipTransientField,
- /**
- * @since 1.1
- */
- SortField,
- /**
- * @since 1.1.1
- */
- @Deprecated
- WriteTabAsSpecial,
- /**
- * @since 1.1.2
- */
- PrettyFormat,
- /**
- * @since 1.1.2
- */
- WriteClassName,
- /**
- * @since 1.1.6
- */
- DisableCircularReferenceDetect,
- /**
- * @since 1.1.9
- */
- WriteSlashAsSpecial,
- /**
- * @since 1.1.10
- */
- BrowserCompatible,
- /**
- * @since 1.1.14
- */
- WriteDateUseDateFormat,
- /**
- * @since 1.1.15
- */
- NotWriteRootClassName,
- /**
- * @since 1.1.19
- */
- DisableCheckSpecialChar,
- /**
- * @since 1.1.35
- */
- BeanToArray
- ;
- private SerializerFeature(){
- mask = (1 << ordinal());
- }
- private final int mask;
- public final int getMask() {
- return mask;
- }
- public static boolean isEnabled(int features, SerializerFeature feature) {
- return (features & feature.getMask()) != 0;
- }
- public static int config(int features, SerializerFeature feature, boolean state) {
- if (state) {
- features |= feature.getMask();
- } else {
- features &= ~feature.getMask();
- }
- return features;
- }
- }
相關文章
- FastJson中迴圈引用的問題ASTJSON
- fastjson字串轉JSON的$ref問題ASTJSON字串
- 怎麼解決引用計數 GC 的迴圈引用問題?GC
- 解決fastjson反序列化時報錯的問題ASTJSON
- 解決迴圈引用
- fastjson:物件轉化成json出現$refASTJSON物件
- require()迴圈引用問題UI
- FastJson使用詳解ASTJSON
- SpringBoot 迴圈引用解決辦法Spring Boot
- Unity容器建構函式引數迴圈引用問題及解決Unity函式
- JavaScript 深複製的迴圈引用問題JavaScript
- Block迴圈引用的三種解決方式BloC
- NSTimer迴圈引用的幾種解決方案
- 如何解決使用JSON.stringify時遇到的迴圈引用問題JSON
- iOS | 用於解決迴圈引用的block timeriOSBloC
- Fastjson SecASTJSON
- Fastjson妙用之@JSONField註解ASTJSON
- ARC下的block導致的迴圈引用問題解析BloC
- SpringBoot中,使用 fastjson代替jacksonSpring BootASTJSON
- Spring如何解決迴圈引用Spring
- 【Fastjson】Fastjson反序列化由淺入深ASTJSON
- Java -fastjson apiJavaASTJSONAPI
- fastjson應用ASTJSON
- fastjson整理思路ASTJSON
- Flask中的迴圈引用/匯入問題演示以及解決方案 | 藍圖的使用與解析 | 藍圖額外用法Flask
- 迴圈引用
- 透過迴圈引用問題來分析Spring原始碼Spring原始碼
- com.alibaba.fastjson.JSONObject cannot be cast to XXX異常解決ASTJSONObject
- 使用c#強大的表示式樹實現物件的深克隆之解決迴圈引用的問題C#物件
- 淺談Gson和fastjson使用中的坑ASTJSON
- Swift與OC真正去理解Block解決迴圈引用的技巧SwiftBloC
- Python迴圈引用是什麼?如何避免迴圈引用?Python
- alibaba/fastjson 之 JSONPathASTJSON
- fastjson @JSONField與SerializerFeatureASTJSON
- iOS迴圈引用iOS
- Spring 迴圈依賴的三種方式(三級快取解決Set迴圈依賴問題)Spring快取
- 阿里巴巴fastjson @JSONField 註解說明阿里ASTJSON
- fastjson使用說明文件ASTJSON