解决FastJson中"$ref重复引用"的问题方法

所属分类: 软件编程 / java 阅读数: 39
收藏 0 赞 0 分享

解决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));
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

java实现背单词程序

这篇文章主要为大家详细介绍了java实现背单词程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

java实现单词查询小程序

这篇文章主要为大家详细介绍了java实现单词查询小程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Java程序开发环境配置图文教程

这篇文章主要为大家详细介绍了Java程序开发环境配置图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

详解ssh框架原理及流程

在本文中小编给大家整理的是关于ssh框架原理及流程的相关知识点内容,有此需要的朋友们可以学习下。
收藏 0 赞 0 分享

Java实现弹窗效果的基本操作

这篇文章主要为大家详细介绍了Java实现弹窗效果的基本操作,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

详解springmvc常用5种注解

在本篇里我们给大家总结了关于springmvc常用5种注解相关知识点以及实例代码,需要的朋友们参考下。
收藏 0 赞 0 分享

Java实现弹窗效果的基本操作(2)

这篇文章主要为大家详细介绍了Java实现弹窗效果的基本操作第二篇,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Spring Boot假死诊断实战记录

这篇文章主要给大家介绍了关于Spring Boot假死诊断的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Spring Boot具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
收藏 0 赞 0 分享

Java计时新姿势StopWatch详解

这篇文章主要介绍了Java计时新姿势StopWatch,最近公司来了个大佬,从他那里学到不少东西,其中一个就是计时的新姿势「StopWatch」,需要的朋友可以参考下
收藏 0 赞 0 分享

java实现点击按钮弹出新窗体功能

这篇文章主要为大家详细介绍了java实现点击按钮弹出新窗体功能,旧窗体不进行操作,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享
查看更多