FastJson序列化导致的 “$ref“

前言:

刚转后端没多久,在通过RPC调用其他组的服务的时候,其他组对接的同学说,你的入参是有问题的,然后他把入参发我,类似于下面的 json

{
	"addressMO": {
		"roomNumber": "1002",
		"street": "上海市徐汇区田林街道"
	},
	"age": 10,
	"brotherMO": {
		"addressMO": {
			"$ref": "$.addressMO"
		},
		"className": "上海中学",
		"name": "我是哥哥"
	},
	"name": "我是弟弟"
}

这个对象包含一个 addressMObrotherMO以及 nameagebrotherMO 中也包含了addressMO,就会导致 出现上面的 "$ref": "$.addressMO",这个其实表示的是引用根目录中的 addressMO 对象。

这个例子其实是我简化后的 demo,为了简单说明。其他的 对象如下:

public static class PersonMO {
        private String name;
        private int age;
        private AddressMO addressMO;
        private BrotherMO brotherMO;

        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;
        }

        public AddressMO getAddressMO() {
            return addressMO;
        }

        public void setAddressMO(AddressMO addressMO) {
            this.addressMO = addressMO;
        }

        public BrotherMO getBrotherMO() {
            return brotherMO;
        }

        public void setBrotherMO(BrotherMO brotherMO) {
            this.brotherMO = brotherMO;
        }
    }

    public static class AddressMO {
        private String street;
        private String roomNumber;

        public String getStreet() {
            return street;
        }

        public void setStreet(String street) {
            this.street = street;
        }

        public String getRoomNumber() {
            return roomNumber;
        }

        public void setRoomNumber(String roomNumber) {
            this.roomNumber = roomNumber;
        }
    }

    public static class BrotherMO {
        private String name;
        private String className;
        private AddressMO addressMO;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getClassName() {
            return className;
        }

        public void setClassName(String className) {
            this.className = className;
        }

        public AddressMO getAddressMO() {
            return addressMO;
        }

        public void setAddressMO(AddressMO addressMO) {
            this.addressMO = addressMO;
        }
    }

测试代码如下:

 @Test
    public void testJSON() {
        AddressMO addressMO = new AddressMO();
        addressMO.setStreet("上海市徐汇区田林街道");
        addressMO.setRoomNumber("1002");


        BrotherMO brotherMO = new BrotherMO();
        brotherMO.setName("我是哥哥");
        brotherMO.setAddressMO(addressMO);
        brotherMO.setClassName("上海中学");

        PersonMO personMO = new PersonMO();
        personMO.setName("我是弟弟");
        personMO.setAge(10);
        personMO.setAddressMO(addressMO);
        personMO.setBrotherMO(brotherMO);

        String ss = JSON.toJSONString(personMO);
        System.out.println("ss ===== " +ss);
    }

可以看到,对于一个对象,当其首次出现时,FastJson 的序列化是正常工作的,但是当其重复出现时,就会变为对象的引用。这是FastJson内部存在一些特殊逻辑,问题产生的原因在于FastJson存在循环/重复引用检测特性,并且该特性是缺省开启的。
实体转化为json字符串后出现了$ref字样的东西,这是因为在传输的数据中出现相同的对象时,fastjson 默认开启引用检测将相同的对象写成引用的形式,引用是通过"$ref"来表示的。

FastJson序列化导致的 “$ref“_第1张图片
修改也很简单,就是在 BrotherMO 中设置 AddressMO 对象是,通过 Copy AddressMO 对象的属性就行了,如下:
FastJson序列化导致的 “$ref“_第2张图片
就能正常输出了,其中的 DozerBeanMapper 是开源库,用来复制对象属性的。

{
	"addressMO": {
		"roomNumber": "1002",
		"street": "上海市徐汇区田林街道"
	},
	"age": 10,
	"brotherMO": {
		"addressMO": {
			"roomNumber": "1002",
			"street": "上海市徐汇区田林街道"
		},
		"className": "上海中学",
		"name": "我是哥哥"
	},
	"name": "我是弟弟"
}

其实不改也是没问题的,通过反序列化出来的 PersonMO 对象都是正常的。
FastJson序列化导致的 “$ref“_第3张图片
刚开始,其他同事跟我说的时候我是很懵逼的,完全不知道,因为我调用他的服务之前是加了日志的,都是正常的,但是同事说的是这个服务上线2年多了,肯定不是他们的问题,哈哈,然后 google 了下,记录下,怕自己会忘记。

你可能感兴趣的:(点滴记录,java,servlet,jvm)