環境
fastjson 1.2.41
問題說明
FastJson 問題
在json對象中有多個地方引用了相同的對象,在經過幾次轉換轉為json字符串的時候會出現占位符,
然后使用fastjson 解析字符串也能正確解析,但使用其他json類庫解析,無法正常還原數據,還是占位符
測試代碼
/**
* FastJson 問題
* 測試 JSONArray(幾個元素有關聯,引用了相同得對象) -> 轉為List -> 加入到 JSONObject 中 -> 最后轉為 json 字符串 打印的時候(最后一步得時候會出現占位符)
* -> 然后再轉為 JSONObject 的時候,非FastJson解析會出現問題(fastJson 解析正常,但是其他json類庫處理時,不會對占位符處理,最后直接就原樣的將值解析成占位符)
* 測試
* testTransfer1 僅僅數據一樣,但是實際上是幾個不同的對象(數據相同,對象不同),經過上述變化,未出現占位符
* testTransfer2 是從某一元素上取得數據(同一個對象,在json對象中,多個地方都有引用)在添加到該jsonArray 上,經過上述變化,會出現占位符
*/
@Test
public void name() {
// testTransfer1();
testTransfer2();
}
private void testTransfer1() {
// [{"one":1,"two":2,"tickets":[{"one":2,"two":3},{"one":3,"two":4}]},{"one":2,"two":3},{"one":3,"two":4}]
String str = "[{\"one\":1,\"two\":2,\"tickets\":[{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]},{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]";
JSONArray array = JSON.parseArray(str);
List<Object> objects = array.toJavaList(Object.class);
JSONObject object = new JSONObject();
object.put("list", objects);
System.out.println(object);
// 經過測試發現如果,不直接用從某個元素中取數據,在添加到該jsonArray 本身,即使他們數據有重合的(數據相同,但不是同一個對象),也不會出現 占位符的現象
}
private void testTransfer2() {
// [{"one":1,"two":2,"tickets":[{"one":2,"two":3},{"one":3,"two":4}]]
String str = "[{\"one\":1,\"two\":2,\"tickets\":[{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]}]";
JSONArray array = JSON.parseArray(str);
// 這里添加
JSONArray tickets = array.getJSONObject(0).getJSONArray("tickets");
for (int i = 0; i < tickets.size(); i++) {
array.add(tickets.get(i));
}
List<Object> list = array.toJavaList(Object.class);
// 以下代碼說明 FastJson 在之后 轉為 json 字符串 ,然后再解析為 json 對象時處理正常(能正常解析)
JSONObject object = new JSONObject();
object.put("list",list);
String jsonStr = object.toJSONString();
System.out.println(jsonStr);
JSONArray list1 = JSON.parseObject(jsonStr).getJSONArray("list");
System.out.println(list1);
// 切換 為 其他 json類庫處理,例如:jackson
ObjectMapper mapper = new ObjectMapper();
try {
Object o = mapper.readValue(jsonStr, Object.class);
System.out.println(o);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
// 內部 從 某一個 元素取出數據,在添加到 jsonArray 上, 經過 上述轉換 (JSONArray(幾個元素有關聯) -> 轉為List -> 加入到 JSONObject 中 -> 轉為 json 字符串),最后會變成這樣
// {"list":[{"tickets":[{"one":2,"two":3},{"one":3,"two":4}],"one":1,"two":2},{"$ref":"$.list[0].tickets[0]"},{"$ref":"$.list[0].tickets[1]"}]}
}
解決辦法
- 去除對象的互相引用關系
- "對象 -> json" 和 "json -> 對象" 兩步轉換統一都用fastJson 類庫處理,
- 禁用FastJson的“循環引用檢測”特性。- 禁用FastJson的“循環引用檢測”特性。
參考:https://www.cnblogs.com/zjrodger/p/4630237.html
參考:https://blog.csdn.net/fly910905/article/details/81504388
/**
* 禁用 fastjson 的 循環引用檢測
* 使用 SerializerFeature.DisableCircularReferenceDetect
*/
private void testTransfer3() {
String str = "[{\"one\":1,\"two\":2,\"tickets\":[{\"one\":2,\"two\":3},{\"one\":3,\"two\":4}]}]";
JSONArray array = JSON.parseArray(str);
// 這里添加
JSONArray tickets = array.getJSONObject(0).getJSONArray("tickets");
for (int i = 0; i < tickets.size(); i++) {
array.add(tickets.get(i));
}
// 全局關閉
// JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
// 該次解析關閉
// 轉為 json 字符串的時候,禁用了 fastjson 的 循環檢測引用特性
String s = array.toJSONString(array, SerializerFeature.DisableCircularReferenceDetect);
// System.out.println(array.toJSONString());
System.out.println(s);
}
說明
由於springboot 默認使用 jackson 處理json 請求,所以需要注意
由於時間問題,這個地方只是發現情況會出現這種問題,至於對象引用會不會出現這種問題,沒有進行實驗,也沒有對fastjson 源碼進行解讀