FastJson 处理json数据中对象相互引用,最后转为json字符串出现占位符("$ref"标识循环引用)"的问题
环境
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 源码进行解读
赞 (0)