前言
项目中用json形式来存储一个集合对象,用fastjson发现多了一些东西:$ref,了解之后才发现是重复引用的问题,现在总结一下
重复引用问题代码
类定义:
public static class Box{
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
调试代码:
Box oneBox = new Box();
oneBox.setId(1);
oneBox.setName("one");
Box twoBox = new Box();
twoBox.setId(2);
twoBox.setName("two");
Box thrBox = new Box();
thrBox.setId(3);
thrBox.setName("thr");
List<Box> boxList = Lists.newArrayList();
boxList.add(oneBox);
boxList.add(oneBox); // 此地方重复加入了oneBox 对象
boxList.add(twoBox);
boxList.add(thrBox);
String strBoxList= JSON.toJSONString(boxList);
System.out.println(strBoxList);
// 结果:
[{"id":1,"name":"one"},{"$ref":"$[0]"},{"id":2,"name":"two"},{"id":3,"name":"thr"}]
循环引用
代码
// 类定义
public static class Tree{
private int id;
private String name;
private Tree nextTree;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Tree getNextTree() {
return nextTree;
}
public void setNextTree(Tree nextTree) {
this.nextTree = nextTree;
}
}
调试代码:
Tree oneTree = new Tree();
oneTree.setId(1);
oneTree.setName("one");
Tree twoTree = new Tree();
twoTree.setId(2);
twoTree.setName("two");
twoTree.setNextTree(oneTree);
Tree thrTree = new Tree();
thrTree.setId(3);
thrTree.setName("thr");
thrTree.setNextTree(oneTree);
oneTree.setNextTree(twoTree);
List<Tree> boxList = Lists.newArrayList();
boxList.add(oneTree);
boxList.add(twoTree);
boxList.add(thrTree);
String strBoxListTwo = JSON.toJSONString(boxList);
System.out.println(strBoxListTwo);
// 运行结果:
[{"id":1,"name":"one","nextTree":{"id":2,"name":"two","nextTree":{"$ref":".."}}},{"$ref":"$[0].nextTree"},{"id":3,"name":"thr","nextTree":{"$ref":"$[0]"}}]
解决问题
- 1、对数据进行转换,new 一个新对象,然后赋值。
- 2、采用fastjson的特性,JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);
此方法有风险,引用检测是FastJson提供的一种避免运行时异常的优良机制,如果关闭它,会有很大可能导致循环引用时发生StackOverflowError异常。这也是FastJson默认开启引用检测的原因。 - 3、循环引用应该是代码逻辑问题,大家尽可能的避免这类问题。
fastjson其他坑
- 在使用Set类型时,不要加范型参数,否则会出现类似com.alibaba.fastjson.JSONArray cannot be cast to java.util.Set这样的错误(目前请尽量避免使用Set作为参数类型吧)
2、使用JSON形式的序列化技术时,所有通信传递的对象必须设置无参的默认构造函数
3、当传递的对象属性中存在内部类时,请保证内部类为static的,不支持对象内部类
4、fastjson传递的参数中不要和其他形式的json对象混用,如net.sf.json、org.json、gson等等,会出现不兼容
5、fastjson默认根据get和set方法来生成json体中的属性键值对,所以同个属性的set方法不要重载,保证简单,负责会出现不确定的赋值后状态
6、针对Bool类型的属性的getXXX和isXXX方法会存在冲突,具体以哪一个为准还不确定,所以请保证你的POJO对象只会存在一种