迴圈引用導致的json序列化失敗

gary-liu發表於2018-09-23

問題

昨天在給系統加日誌後,系統就一直報 Stack Overflow錯誤,找了很久才發現問題,引入的日誌工具使用 gson序列化,而列印的日誌物件裡包含迴圈引用,導致出錯。

簡單復現

/**
 * ClassName: SerializeModel <br/>
 * Function: 迴圈引用序列化<br/>
 * 迴圈引用:包括自迴圈,如本類和A、B互相引用 (感覺都是類設計的不好啊)
 *
 * stackOverflowError分析原因:當序列化引擎解析A時,它發現這個物件持有一個B的引用,轉而去解析B。解析B時,發現他又持有A的引用,又轉回A。如此產生StackOverflowError異常。
 *
 * @author gary.liu
 * @date 2018/9/23
 */
public class SerializeModel {

    private int id;

    private List<SerializeModel> models;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public List<SerializeModel> getModels() {
        return models;
    }

    public void setModels(List<SerializeModel> models) {
        this.models = models;
    }

    public String toString(){
        return ToStringBuilder.reflectionToString(this);
    }

    public static void main(String[] args) {
        List<SerializeModel> models = Lists.newArrayList();
        SerializeModel model = new SerializeModel();
        model.setId(1);
        models.add(model);
        model.setModels(models);

        System.out.println(ToStringBuilder.reflectionToString(model));
        System.out.println(JSON.toJSONString(model));
        System.out.println(JSON.toJSONString(ToStringBuilder.reflectionToString(model)));

        //下面會報stackoverflow error
        System.out.println(new Gson().toJson(model));
        System.out.println(JSON.toJSON(model));
        System.out.println(JSON.toJSONString(model, SerializerFeature.DisableCircularReferenceDetect));

    }

}

解決辦法

由於我只是想列印日誌,所以就只想到下面兩個辦法:

  1. 使用 ToStringBuilder.reflectionToString
  2. 使用 fastjson 的 JSON.toJSONString ,fastjson會預設迴圈引用處理成 $ref,不會報錯

相關文章