解决FastJson中"$ref重复引用"的问题方法
解决FastJson中"$ref重复引用"的问题,先来看一个例子吧:
public static void main(String[] args) { UserGroup userGroup = new UserGroup().setName("UserGroup"); User user = new User("User"); for (int i = 0; i < 3; i++) { userGroup.addUser(user); } Console.log(JSON.toJSONString(userGroup)); } @Data @AllArgsConstructor static class User { private String name; } @Data @Accessors(chain = true) static class UserGroup { private String name; private List<User> users = Lists.newArrayList(); public UserGroup addUser(User user) { this.getUsers().add(user); return this; } }
输出结果:
{"name":"UserGroup","users":[{"name":"User"},{"$ref":"$.users[0]"},{"$ref":"$.users[0]"}]}
<!--- more --->
上面的现象就是将user对象的引用重复使用造成了重复引用问题,Fastjson默认开启引用检测将相同的对象写成引用的形式:
{"$ref": "$"} // 引用根对象 {"$ref":"@"} // 引用自己 {"$ref":".."} // 引用父对象 {"$ref":"../.."} // 引用父对象的父对象 {"$ref":"$.members[0].reportTo"} // 基于路径的引用
目前来说,前端还没有一个很好的办法来解析这样的JSON格式。
除了上面的重复引用外, 还衍生出了另外一个概念:"循环引用",下面来看下两者之间的区别吧:
- 重复引用:指一个对象引用重复出现多次
- 循环引用:对象A引用对象B,对象B引用对象A(这种情况一般是个雷区,轻易不要尝试的好,很容易引发StackOverflowError)
再来看一个循环引用的例子:
public static void main(String[] args) { Order order = new Order().setName("Order"); Item item = new Item().setName("Item"); item.setOrder(order); order.setItem(item); Console.log(JSON.toJSONString(order)); Console.log("----------------------------"); Console.log(JSON.toJSONString(item)); } @Data @Accessors(chain = true) static class Order { private String name; private Item item; } @Data @Accessors(chain = true) static class Item { private String name; private Order order; }
{"item":{"name":"Item","order":{"$ref":".."}},"name":"Order"}
----------------------------
{"name":"Item","order":{"item":{"$ref":".."},"name":"Order"}}
解决方案
关闭FastJson引用检测机制(慎用,循环引用时可能导致StackOverflowError)
JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect)
避免循环引用(某一方的引用字段不参与序列化:@JSONField(serialize=false))
避免一个对象引用被重复使用多次(使用拷贝的对象副本来完成JSON数据填充)
public static void main(String[] args) { UserGroup userGroup = new UserGroup().setName("UserGroup"); User user = new User("User"); for (int i = 0; i < 3; i++) { User duplicateUser = new User(); BeanUtil.copyProperties(user, duplicateUser); userGroup.addUser(duplicateUser); } Console.log(JSON.toJSONString(userGroup)); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
相关文章
springboot实现在工具类(util)中调用注入service层方法
这篇文章主要介绍了springboot实现在工具类(util)中调用注入service层方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2021-06-06springboot yml中profiles的巧妙用法(小白必看多环境配置)
这篇文章主要介绍了springboot yml中profiles的巧妙用法,非常适合多环境配置场景,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2021-04-04Java经典算法汇总之顺序查找(Sequential Search)
Java查找算法之顺序查找说明:顺序查找适合于存储结构为顺序存储或链接存储的线性表。 下面我们来详细说明下2016-04-04Java使用list集合remove需要注意的事项(使用示例)
List集合的一个特点是它其中的元素是有序的,也就是说元素的下标是根据插入的顺序来的,在删除头部或者中间的一个元素后,后面的元素下标会往前移动,本文给大家介绍Java使用list集合remove需要注意的事项,感兴趣的朋友一起看看吧2022-01-01SpringCloud OpenFeign 服务调用传递 token的场景分析
这篇文章主要介绍了SpringCloud OpenFeign 服务调用传递 token的场景分析,本篇文章简单介绍 OpenFeign 调用传递 header ,以及多线程环境下可能会出现的问题,其中涉及到 ThreadLocal 的相关知识,需要的朋友可以参考下2022-07-07
最新评论