fastjson使用JSONObject.toJSONString()出现:“$ref“:“$.XXX“的解决方法

问题描述

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 数据,可能某些特性不是我们所需要的,但并不能掩盖它的强大与好用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值