80357518 2019-06-29
解决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格式。
除了上面的重复引用外, 还衍生出了另外一个概念:"循环引用",下面来看下两者之间的区别吧:
再来看一个循环引用的例子:
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"}}StackOverflowError)JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect)
@JSONField(serialize=false))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));
}