解決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;
   }
}

輸出結果:java

{"name":"UserGroup","users":[{"name":"User"},{"$ref":"$.users[0]"},{"$ref":"$.users[0]"}]}

<!--- more --->
上面的現象就是將user對象的引用重複使用形成了重複引用問題,Fastjson默認開啓引用檢測將相同的對象寫成引用的形式:json

{"$ref": "$"} // 引用根對象
{"$ref":"@"} // 引用本身
{"$ref":".."} // 引用父對象
{"$ref":"../.."} // 引用父對象的父對象
{"$ref":"$.members[0].reportTo"} // 基於路徑的引用

目前來講,前端尚未一個很好的辦法來解析這樣的JSON格式。this

除了上面的重複引用外, 還衍生出了另一個概念:"循環引用",下面來看下二者之間的區別吧:code

  • 重複引用:指一個對象引用重複出現屢次
  • 循環引用:對象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));
}
相關文章
相關標籤/搜索