fastjson:对象转化成json出现$ref

文章介绍了在使用Fastjson时遇到的对象重复引用问题,导致json字符串中出现$ref。分析了循环引用和重复引用的区别,并提供了五种解决方案,包括局部关闭引用检测、全局配置、创建新对象、禁止序列化以及字段注解指定序列化方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题现象

/**
 * fastjson中$ref对象重复引用问题
 */
public class TestFastJson {
 
    List<Person> list = new ArrayList<Person>();
    Person p = new Person("FLY", 25);
 
    /**
     *  测试main
     */
    public static void main(String[] args) {
        new TestFastJson().test1();
 
    }
 
    /**
     * 未关闭引用检测,转化字符串时会出现$ref
     */
    public void test1() {
        list.add(p);
        list.add(p);
        String jsonStr = JSON.toJSONString(list);
        System.out.println(jsonStr);
        // [{"age":25,"name":"FLY"},{"$ref":"$[0]"}]
 
    }
 
    
 
}
 
class Person {
    private String name;
    private int age;
 
    // 构造函数
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

问题分析

  • 实体转化为json字符串后出现了$ref字样的东西,这是因为在传输的数据中出现相同的对象时,fastjson默认开启引用检测将相同的对象写成引用的形式
  • 引用是通过"$ref"来表示的
引用描述
“$ref”:“…”上一级
“$ref”:“@”当前对象,也就是自引用
r e f " : " ref":" ref":"根对象
r e f " : " ref":" ref":".children.0”基于路径的引用,相当于 root.getChildren().get(0)
  • 说到引用分为两种,重复引用和循环引用

循环引用:即A对象引用B对象,B对象又引用A对象,这种情况是要极力避免的,因为会导致堆栈溢出(StackOverflowError);
重复引用:上面的例子就是因为相同的订单对象出现在两个集合中,所以第二个orderList集合中直接返回的是$ref。一般大家在写代码的过程中,如果出现$ref,通常应该是重复引用问题。

问题解决

1.局部关闭

将该对象在后端转换为json字符串返回给前端,使用SerializerFeature.DisableCircularReferenceDetect关闭循环引用。

String jsonString=JSON.toJSONString(object, SerializerFeature.DisableCircularReferenceDetect);

2.全局配置关闭

可以在SpringBoot项目的json配置中将循环引用关闭。FastJson的.java配置增加以下项:

fastConverter.setFeatures(SerializerFeature.DisableCircularReferenceDetect);

or

JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();

但是因为全局配置是在我们项目的基础jar包中配置的,改动基础jar包会有风险,会对前面所有的依赖项目产生影响。所以也不采用这种方式。

大家想想为什么fastjson默认是开启这个功能的就知道原因了。如果全局关闭,性能也会有极大影响。

3.new新的对象来避免

我们可以将List中的对象使用BeanUtil这样的工具,拷贝为新的对象。(BeanUtil创建出来的对象跟原来的对象不是同一个对象)

4.禁止序列化

如果循环引用的数据,前端用不到,那可以在实体类对应的字段加注解禁止序列化,这样前端就不会接收到这个字段的引用数据了。

    @JSONField(serialize = false)
	private List<Order> orderList;

5.在该字段的注解上指定序列化时关闭循环引用

但是很多时候,前端又需要这个数据,所以禁止序列化也是不行滴,接下来看另外一种注解解决方式。

    @JSONField(serialzeFeatures = {SerializerFeature.DisableCircularReferenceDetect})
	private List<Object> objectList;
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值