FastJson序列化导致的 “$ref“

news2024/11/19 8:21:09

前言:

刚转后端没多久,在通过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"来表示的。

在这里插入图片描述
修改也很简单,就是在 BrotherMO 中设置 AddressMO 对象是,通过 Copy AddressMO 对象的属性就行了,如下:
在这里插入图片描述
就能正常输出了,其中的 DozerBeanMapper 是开源库,用来复制对象属性的。

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/492255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

795. 前缀和(C++和Python3)——2023.5.5打卡

文章目录 QuestionIdeasCode Question 输入一个长度为 n 的整数序列。 接下来再输入 m 个询问,每个询问输入一对 l,r 。 对于每个询问,输出原序列中从第 l 个数到第 r 个数的和。 输入格式 第一行包含两个整数 n 和 m 。 第二行包含 n 个整数&#…

哪种类型蓝牙耳机佩戴最舒服?公认佩戴舒适度高的蓝牙耳机

随着都市人生活水准的提高,人们开始享受起生活,观察身边的事物,佩戴蓝牙耳机能够满足自身基本通勤需求,现阶段不少蓝牙耳机质量越来越好,并且在功能、体验、技术上都具有相当的优势,性价比极高,…

Window下的反弹shell

什么是正向shell? 正向shell:控制端主动发起连接请求去连接被控制端,中间网络链路不存在阻碍。 反向shell:被控制端主动发起连接去请求连接控制,通常被控端由于防火墙受限制、权限不足、端口被占用等问题导致被控端不能正常接收…

短视频矩阵管理营销系统.源代码

一、短视频矩阵系统一般拥有以下几个主要功能: 1. 视频拍摄和剪辑功能,让用户轻松制作和发布短视频内容。 2. 视频分发和推广功能,矩阵管理发布、将制作好的短视频内容推送到各大短视频平台,实现效果最大化。 3. 数据监测和分析…

计算机三级嵌入式系统开发 知识点笔记

目录为搜索词,详情看每一节后图片 思维导图已上传,点击这里下载 嵌入式系统开发 全部章节图片第一章 嵌入式系统概论1.1SoCIP核 1.21.2.1ASCIIGB2312GB18030UTF8UTF16超文本字符形状两种描述方法 1.2.2数字图像 1.2.3音频 1.3传输介质分为 有线通信 和 无…

Windows下安装MySQL数据库+Navicat (从完全卸载到安装使用图文详细步骤,附安装包)

目录 第一章:如何完全卸载干净mysql教程(三个步骤完全卸载)1)步骤一:卸载程序2)步骤二:删除文件3)步骤三:删除注册表信息 第二章:下载软件两种方式1&#xff…

架构师日记-深入理解软件设计模式 | 京东云技术团队

作者:京东零售 刘慧卿 一 设计模式与编程语言 1.1 什么是设计模式 设计模式(Design pattern) :由软件开发人员在软件开发中面临常见问题的解决方案,是经过长时间的试验积累总结出来的,它使设计更加灵活和…

MyBatis详细笔记

核心知识点 核心配置文件 映射文件概述 Dao层实现与代理开发实现 自动映射与自定义映射 参数传递与返回值 动态SQL 注解开发 缓存机制 总结 核心配置文件【mybatis-config.xml】 MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 位置:resourc…

前端配置化表单组件设计方法 | 京东云技术团队

一、背景 前端开发中涉及表单的页面非常多,看似功能简单,开发快速,实则占去了很大一部分时间。当某个表单包含元素过多时还会导致html代码过多,vue文件过大。从而不容易查找、修改和维护。为了提高开发效率及降低维护成本&#x…

基于max30102的物联网病房监测系统(中断处理和主题逻辑)

目录 五、中断处理 六、主体框架 对采集数据的初始化 核心功能的实现 烟雾 通信帧格式 wifi接收数据的处理 OLED显示 五、中断处理 void SysTick_Handler(void) {TimingDelay_Decrement(); }void ESP8266_USART_INT_FUN(void) {uint8_t ucCh;if ( USART_GetITStatus (…

platform总线五级匹配解析

代码来源:开源linux内核linux-6.2.9 platform总线设备与驱动的匹配 对于device和driver无论哪个创建都会尝试主动寻找对方进行绑定,而platform bus总线的匹配原则如上面的代码所示,共有五级匹配,这里进行详细解析下: …

WRF模式

随着生态文明建设和“碳中和”战略的持续推进,我国及全球气候变化及应对是政府、科学界及商业界关注的焦点。气候是多个领域(生态、水资源、风资源及碳中和等问题)的主要驱动因素,合理认知气候变化有利于解释生态环境变化机理及过…

Android应用层开发学习 Framework 是必须的吗?

作为一名应用层 App 开发工程师,我们为什么要学习 Android Framework?答案很简单,为了不被淘汰!在 2023 年的当下,不会点 Binder WMS AMS PMS 好像都找不到工作了,更过分的是应聘企业甚至希望你会点 RN Fluter 等跨平台…

元宇宙的重要底层技术

在元宇宙中,人们可以通过数字分身、化身(可理解为虚拟化身)、社交媒体化身和智能代理进行交互,这背后都需要底层技术支持。元宇宙的底层技术主要包括: VR/AR、5G/6G、区块链和人工智能。 VR/AR是元宇宙的主要交互设备…

JAVA新提案:努力简化Hello World写法

OpenJDK 的 JEP 445 提案正在努力简化 Java 的入门难度。这个提案主要是引入 “灵活的 Main 方法和匿名 Main 类” ,希望 Java 的学习过程能更平滑,让学生和初学者能更好地接受 Java 。 提案的作者 Ron Pressler 解释:现在的 Java 语言非常适…

ES6-迭代器和生成器

一、迭代器概念 遍历器( Iterator )就是一种机制。它是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。 1) ES6 创造了一种新的遍历命令 for...of 循环&#…

虹科方案 | 助力高性能视频存储解决方案-2

上篇文章《虹科方案 | 助力高性能视频存储解决方案-1》我们分享了虹科&ATTO 和 Avid 共同创建协作解决方案,助力高性能视频存储,今天我们再深入介绍一下我们的案例详情。 一、行业挑战 从高端广播设施到小型独立工作室的媒体后期制作环境都需要允许多…

【C++】STL标准库之list

STL标准库之list list类的简介常用的list类的接口构造迭代器容量访问修改 list和vector的区别 list类的简介 list是一种序列式容器,可以在任意位置插入和删除元素,并且其时间复杂度为O(1),在底层,list是双向链表结构,…

《CTFshow-Web入门》08. Web 71~80

Web 71~80 web71知识点题解 web72知识点题解 web73题解 web74题解 web75知识点题解 web76题解 web77知识点题解 web78知识点题解 web79题解 web80知识点题解 ctf - web入门 web71 知识点 ob_get_contents():得到输出缓冲区的内容。ob_end_clean():清除…

程序员:面试造飞机,入职拧螺丝?真难···

刚开始工作的时候,我也想不通这个问题,甚至很鄙视这种现象。后面当了面试官,做到了公司中层管理,也会站在公司以及行业角度去重新思考这个问题。 为什么这种现象会越来越普遍呢?尤其在 IT 行业愈加明显。 面试看的是…