1. 案例代码
1.1 案例一
多个元素持有同一个引用时。
案例代码:
public class TestFastJson {
public static void main(String[] args) {
ceshi();
}
public static void ceshi(){
List<User> list = new ArrayList<>();
//注意:此处的对象为同一个
User user = new User();
for (int i = 0; i <3 ; i++) {
user.setName("李白");
user.setAge("20");
list.add(user);
}
String string = JSON.toJSONString(list);
System.out.println(string);
}
@Data
public static class User {
private String name;
private String age;
}
}
响应结果:
[{"age":"20","name":"李白"},{"$ref":"$[0]"},{"$ref":"$[0]"}]
1.2 案例二
多个元素内部持有同一个引用时。
public class TestFastJson {
public static void main(String[] args) {
test2();
}
public static void test2() {
List<UserPo> userPos = new ArrayList<>();
//注意:此处的引用是一个
List<Order> o1s = new ArrayList<>();
Order o1 = new Order();
o1.setId(100L);
o1.setOrderName("水瓶");
o1s.add(o1);
UserPo u1 = new UserPo();
u1.setId(1L);
u1.setAge(12);
u1.setUserName("tom");
u1.setPassword("1");
//持有的是同一个order引用
u1.setOrders(o1s);
UserPo u2 = new UserPo();
u2.setId(2L);
u2.setAge(12);
u2.setUserName("tom");
u2.setPassword("2");
//持有的是同一个order引用
u2.setOrders(o1s);
userPos.add(u1);
userPos.add(u2);
System.out.println(JSON.toJSONString(userPos));
}
@Data
public static class UserPo {
private Long id;
private String userName;
private String password;
private Integer age;
private List<Order> orders;
}
}
响应报文:
[{"age":12,"id":1,"orders":[{"id":100,"orderName":"水瓶","price":0.0}],"password":"1","userName":"tom"},{"age":12,"id":2,"orders":[{"$ref":"$[0].orders[0]"}],"password":"2","userName":"tom"}]
2. 解决方案
方案一:通过对象拷贝的方式,使得同一个对象的属性值复制到不同的对象中。
方案二:关闭FastJson的循环引用的检查:
JSON.toJSONString(userPos, SerializerFeature.DisableCircularReferenceDetect)
3. 项目中实际遇到的场景
在实际项目中,我们一般会避免案例代码中的书写方式。
但是还是可能会遇到{"$ref":"$[0]"}
。
- 查询某接口,得到详细数据(无序且存在重复的元素(重复的元素不是同一个引用))。
- 需要对详细数据排序:
2.1 将详细数据转换成Map(注意:此时重复的元素只会保留一个)。
2.2 遍历有序的数据,将详细数据排序(此处会造成多个元素持有一个map中的value引用)。 - 使用FastJson对2的返回结果格式化。
此时,JSON格式化数据的解决方案就是在序列化对象的同时,使用SerializerFeature.DisableCircularReferenceDetect
(关闭引用检查)。