目录
问题描述
fastjson 是 Java 开发中常用的 JSON 处理工具。但在使用 JSONObject.toJSONString() 方法时,会出现返回结果包含 “$ref”: “$.XXX” 这类引用表达式的问题,导致序列化结果异常。
问题复现
引入fastjson依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83</version>
</dependency>
具体代码
1. 情况一
import com.alibaba.fastjson.JSONObject;
public class Demo {
public static void main(String[] args) {
Student student = new Student();
Teacher teacher = new Teacher();
student.setTeacher(teacher);
student.setName("张三");
teacher.setStudent(student);
teacher.setName("老师");
System.out.println(JSONObject.toJSONString(teacher));
}
static class Student{
private String name;
private Teacher teacher;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
static class Teacher{
private String name;
private Student student;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
}
运行结果
{"name":"老师","student":{"name":"张三","teacher":{"$ref":".."}}}
这段代码看似没有问题,但运行时会出现意外的"$ref":"…"字符串。问题的根源在于循环引用:Student类调用了Teacher类,而Teacher类又反过来调用了Student类,形成了相互调用关系。
2.情况二
这种情况是在工作中实际遇到的
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
Student student1 = new Student("张三");
Student student2 = new Student("李四");
List<Student> studentList= new ArrayList<>();
studentList.add(student1);
studentList.add(student2);
Teacher teacher = new Teacher("老师", student1, studentList);
System.out.println(JSONObject.toJSONString(teacher));
}
static class Student{
private String name;
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
static class Teacher{
private String name;
private Student student;
private List<Student> studentList;
public Teacher(String name, Student student, List<Student> studentList) {
this.name = name;
this.student = student;
this.studentList = studentList;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
}
}
运行结果
{"name":"老师","student":{"name":"张三"},"studentList":[{"$ref":"$.student"},{"name":"李四"}]}
出现问题是因为对象Student不仅是对象Teacher中的一个属性,它也是list集合中的一个元素,其实两种情况的本质其实都是代码中出现了循环引用。
解决方案
其实,在仔细查看以上代码后,我们并不能找出代码的任何问题,在工作中,对于这样的代码应该说是司空见惯,但是为什么又会出现我们意想不到的结果呢?其根源还是在我们使用的fastjson上面。
方法一:禁用循环引用的检测
使用fastjson的SerializerFeature.DisableCircularReferenceDetect特性,在序列化时禁用循环引用的检测
JSONObject.toJSONString(teacher, SerializerFeature.DisableCircularReferenceDetect)
方法二:使用@JSONField(serialize = false)注解标记循环引用的属性
情况一中,在Class Teacher中的Student属性上使用@JSONField(serialize = false)注解进行标记
@JSONField(serialize = false)
private Student student;
方法三:创建一个新对象,避免出现循环引用
创建一个新的Student对象student1取代原来的student对象
Student student1 = new Student();
student1.setName("张三");
teacher.setStudent(student1);
总结:
我们可以说这是fastjson的一个坑,一般在使用的使用,我们是很难发现这种问题的存在,只有在测试后才可能发现,好在经过简单的代码改写,便能轻松解决。
fastjson是阿里巴巴开源的功能强大性能极致并且简单易用的Java JSON库。它提供了大量的方法来处理 JSON 数据,可能某些特性不是我们所需要的,但并不能掩盖它的强大与好用。

2255

被折叠的 条评论
为什么被折叠?



