Java对象内部循环引用,导致Fastjson2序列化对象时StackOverflowError

news/2025/3/20 16:34:29/文章来源:https://www.cnblogs.com/lambdadog/p/18783319

Java项目中有用Fastjson2序列化一个map的代码,当map中有一个自定义的InvalidParameterException对象时会StackOverflowError。
简化一下如下:

import com.alibaba.fastjson2.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.x.x.x.x.InvalidParameterException;
import org.junit.jupiter.api.Test;public class JsonErrorTest {/*** 测试Fastjson2*/@Testpublic void fastjson2Test() {InvalidParameterException exception = new InvalidParameterException("test");JSON.toJSONString(exception);}/*** 测试Jackson*/@Testpublic void jacksonTest() throws JsonProcessingException {InvalidParameterException exception = new InvalidParameterException("test");ObjectMapper objectMapper = new ObjectMapper();objectMapper.writeValueAsString(exception);}
}

测试Fastjson2结果如下:

java.lang.StackOverflowErrorat com.alibaba.fastjson2.writer.FieldWriterObject.write(FieldWriterObject.java:205)at com.alibaba.fastjson2.writer.ObjectWriterException.write(ObjectWriterException.java:45)at com.alibaba.fastjson2.writer.FieldWriterObject.write(FieldWriterObject.java:327)at com.alibaba.fastjson2.writer.ObjectWriterException.write(ObjectWriterException.java:45)at com.alibaba.fastjson2.writer.FieldWriterObject.write(FieldWriterObject.java:327)at com.alibaba.fastjson2.writer.ObjectWriterException.write(ObjectWriterException.java:45)at com.alibaba.fastjson2.writer.FieldWriterObject.write(FieldWriterObject.java:327)at com.alibaba.fastjson2.writer.ObjectWriterException.write(ObjectWriterException.java:45)at com.alibaba.fastjson2.writer.FieldWriterObject.write(FieldWriterObject.java:327)at com.alibaba.fastjson2.writer.ObjectWriterException.write(ObjectWriterException.java:45)at com.alibaba.fastjson2.writer.FieldWriterObject.write(FieldWriterObject.java:327)

看到这个报错一开始不知道是什么原因。

测试Jackson结果如下:

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: com.x.x.x.x.InvalidParameterException["rootCause"])at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1277)at com.fasterxml.jackson.databind.ser.BeanPropertyWriter._handleSelfReference(BeanPropertyWriter.java:945)at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:722)at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:755)at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178)at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)at com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4407)at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3661)

可以看到Jackson的报错提示很清晰:com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Direct self-reference leading to cycle (through reference chain: com.x.x.x.x.InvalidParameterException["rootCause"])
是“rootCause”字段引用自己(this)导致的循环引用。通过查看代码,异常类中的确有这样一段代码

public Throwable getRootCause() {Throwable rootCause = this;Throwable cause = getCause();while (cause != null && cause != rootCause) {rootCause = cause;cause = cause.getCause();}return rootCause;}

这是一个get方法,json框架会序列化为rootCause字段,这个方法有可能返回自身,所以造成了循环引用。

解决方法:
1.(推荐)修改类代码,不要循环引用。
2.(不推荐)对于Fastjson2使用框架的检测循环引用的参数来避免报错,代码如下:

/*** 测试Fastjson2*/@Testpublic void fastjson2Test() {InvalidParameterException exception = new InvalidParameterException("test");JSON.toJSONString(exception, JSONWriter.Feature.ReferenceDetection);}

对于Jackson,可以在循环引用字段上加上这些注解@JsonIgnore, @JsonBackReference

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20242934 2024-2025-2 《网络攻防实践》第四周作业

1.实践内容 在网络攻防实验环境中完成TCP/IP协议栈重点协议的攻击实验,包括ARP缓存欺骗攻击、ICMP重定向攻击、SYN Flood攻击、TCP RST攻击、TCP会话劫持攻击。 ARP缓存欺骗攻击:通过伪造ARP消息,欺骗目标设备将攻击者的MAC地址与合法IP地址关联,从而截获或篡改网络数据,造…

ConcurrentHashMap和锁

为什么HashMap数组的长度是2的指数次幂? 因为HashMap的底层是数组+链表+红黑树,在插入元素时,需要通过索引获得插入元素的位置,计算索引的方法是使用哈希函数,将元素的哈希值与数组长度取模,当数组长度是2的指数次幂时,取模操作相当于对元素的哈希值进行二进制位与运算(…

麒麟系统V10系统安全加固

一、安装clamav杀毒软件 1.在clamav官网下载:https://www.clamav.net/downloads 也可以在github上下载早一点的版本:https://github.com/Cisco-Talos/clamav/releases 我这里安装clamav-1.1.2rpm -ivh clamav-1.1.2.linux.x86_64.rpm2.下载病毒库: https://database.clamav.…

孤独摇滚 K-ON wallpapers

双厨狂喜 孤独摇滚K-ON

医疗器械行业IPD流程设计:6个关键问题与解决方案

在当今竞争激烈的医疗器械行业,产品的创新与快速上市能力是企业生存和发展的关键。IPD(集成产品开发)流程作为一种先进的产品开发管理模式,正逐渐成为医疗器械企业提升竞争力的重要手段。然而,在实际应用中,许多企业在 IPD 流程设计方面面临着诸多挑战。本文将深入探讨医…

KUKA库卡KR360_R2830机械臂维修减速机卡住了

库卡机器人维修减速机卡死,作为一种常见的机械故障,其成因往往复杂多样,通常可以归结为长时间的高强度工作、外部异物的侵入、安装过程中的疏忽以及润滑系统的失效等多种因素。以下是对这一故障常见原因的详尽阐述,以及一些实用的维修建议:库卡机器人减速机卡死现象的根源…

【原厂】点阵LED数码管驱动/内置显示RAM为8x16位-LED显示驱动芯片VK1640 SOP28

产品品牌:永嘉微电/VINKA 产品型号:VK1640 封装形式:SOP28 概述 VK1640是一种数码管或点阵LED驱动控制专用芯片,内部集成有数据锁存器、LED 驱 动等电路。SEG脚接LED阳极,GRID脚接LED阴极,可支持8SEGx16GRID的点阵LED显示。 适用于小型LED显示屏驱动。采用SOP28的封装形式…

portainer学习笔记1

Portainer是一款非常好用的docker容器管理平台,部署也很easy。# 创建portainer数据卷 docker volume create portainer_data # 拉取镜像启动portainer docker run -d -p 8000:8000 -p 9443:9443 \ --name portainer --restart=always \ -v /var/run/docker.sock:/var/run/dock…

安装Python保姆级教程(Pycharm破解码+解释器安装)

一、进入Python官网首页,下载最新的Python版本 https://www.python.org/downloads/ 选择最新的Python3.10.5,下载64位的版本 二、下载完成后,进行安装 1.双击Python-3.10.5-amd64.exe 3.出现此页面表示安装成功 三、运行Python 1.Win+R打开控制台,输入Python 此时出现了一…

dify知识库

一、概述 知识库功能将 RAG 管线上的各环节可视化,提供了一套简单易用的用户界面来方便应用构建者管理个人或者团队的知识库,并能够快速集成至 AI 应用中。 开发者可以将企业内部文档、FAQ、规范信息等内容上传至知识库进行结构化处理,供后续 LLM 查询。 相比于 AI 大模型内…

DevOps 平台选型对比:功能与价值剖析

在数字化转型加速的当下,高效的软件开发流程成为企业竞争力的关键。DevOps 平台作为整合开发与运维的重要工具,其选型至关重要。Gitee DevOps 是一款在行业内表现出色的平台,能为企业提供从代码管理到部署上线的全流程支持。通过对其功能、价格、用户体验等多方面与市场竞品…

关于如何搭建anythingllm+ollama(deepseekr1、嵌入模型)+milvus的本地知识库语言模型

这里只是对于自己在部署过程中踩到的坑做个记录。 以anythingllm为平台,接入基于ollama运行deepseekr1通用模型、嵌入模型,使用milvus作为向量数据库。其中milvus和anythingllm均在docker desktop中运行。 一、ollama 1.首先在ollama官网下载并安装ollama。 2.然后在官网的mo…