迴圈引用導致的json序列化失敗
阿新 • • 發佈:2018-12-11
問題
昨天在給系統加日誌後,系統就一直報 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));
}
}
解決辦法
由於我只是想列印日誌,所以就只想到下面兩個辦法:
- 使用 ToStringBuilder.reflectionToString
- 使用 fastjson 的 JSON.toJSONString ,fastjson會預設迴圈引用處理成 $ref,不會報錯