Gson临时文件被删除造成的stackOverflowError

2023-05-16

错误内容

今天使用Gson序列化的时候出现了stackOverflowError的错误,内容如下:

at com.google.gson.Gson.getAdapter(Gson.java:416)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:135)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:105)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:104)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:160)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:96)
	at com.google.gson.Gson.getAdapter(Gson.java:416)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:135)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:105)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:104)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:160)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:96)
	at com.google.gson.Gson.getAdapter(Gson.java:416)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:135)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:105)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:104)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:160)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:96)
	at com.google.gson.Gson.getAdapter(Gson.java:416)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:135)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.<init>(ReflectiveTypeAdapterFactory.java:105)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.createBoundField(ReflectiveTypeAdapterFactory.java:104)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getBoundFields(ReflectiveTypeAdapterFactory.java:160)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.create(ReflectiveTypeAdapterFactory.java:96)
	at com.google.gson.Gson.getAdapter(Gson.java:416)
	at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory.getFieldAdapter(ReflectiveTypeAdapterFactory.java:135)

这个问题我看了很久都没找出问题,终于在同事的帮助下解决了

场景再现

当时是打算写一个切面打印Log,将controller接收的参数使用Gson序列化,注意这个参数是MultipartFile的文件类型,场景如下:

HelloController类:

@Slf4j
@RestController
@RequestMapping("hello")
public class HelloController {

    @Autowired
    private HelloService helloService;

    @PostMapping("dosomething")
    public Result hello(@RequestParam("file") MultipartFile multipartFile) {
           // doSomething();
        }
    }

Log切面:

@Aspect
@Component
@Slf4j
public class LogAspect {

    @Pointcut("execution(* com.controller..*.*(..))")
    private void helloController() {
    }
    
    @Around("helloController()")
    public Object aroundQueryLog(ProceedingJoinPoint pjp) throws Throwable {
        // 逻辑处理。。。。。。。。。。。
        Object[] args = pjp.getArgs(); // 获取HelloController的各个参数
        for (Object arg : args) {
            log.info(new Gson().toJson(arg)); // 序列化每一个参数值
        }
        // 逻辑处理。。。。。。。。。。
    }

}

问题再现并分析

问题:
每次调用hello/dosomething资源,都会报错,就是上文提到的stackOverflowError

分析:

  • 对于MultipartFile类型的参数,Tomcat会在一个特定的目录下临时存放这个文件,正常情况下当访问结束后还会存在一段时间
  • 由于某些原因切面走到序列化参数值之前,controller已经执行完毕并响应结果
  • 公司的服务器在访问结束后,立马删除了这个临时文件

所以当序列化参数值的时候,MultipartFile对象对应的临时文件不存在了,相当于序列化了一个寂寞。
那么导致出现stackOverflowError的元凶就找出来了。‘

从Gson User Guide的解释上看:

If a field is marked transient, (by default) it is ignored and not included in the JSON serialization or deserialization.

By default, if you mark a field as transient, it will be excluded. As
well, if a field is marked as “static” then by default it will be
excluded.

像这种只存在瞬间的对象,最好排除在序列化之外(这里有一个瞬态和静态的概念)

ps : 不知道是否理解正常,但是当看见这句话时,确实是想到了有一个存在临时文件的可能~

解决方案

  1. 要么不序列化带有MultipartFile的参数
  2. 要么使用Base64将输出流转化为Base64格式进行文件的传递与接收

可以根据这个网站进行操作,也可以看我下面这段代码
https://blog.csdn.net/weixin_45562753/article/details/108255263

/**
 * 将文件转成base64编码
 * 
 */
public String getBase64Code(ByteArrayOutputStream byteArrayOutputStream){
  try {
    byte[] bytes = byteArrayOutputStream.toByteArray();
    String base64Str = Base64.getEncoder().encodeToString(bytes);
    return base64Str;
  } catch (Exception e) {
    e.printStackTrace();
  }
  return null;
}

总结

Gson能够导致stackOverflowError的情况,我就见过两种:

  1. 循环引用造成,这个情况的博客有很多了
  2. 遇见临时文件被删除(临时性的)导致
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Gson临时文件被删除造成的stackOverflowError 的相关文章

随机推荐

  • 自学VUE(4)创建项目

    创建项目 1 检查电脑环境 node v npm v vue V cnpm v 2 创建项目 xff0c cd到桌面 xff0c 执行命令 xff1a vue init webpack firstVue 初始化一个项目 3 桌面获得一个项目
  • 前端请求后台报错400

    报错原因 xff1a 前端请求的字段名称或者字段类型和后台编写的实体类不一样 xff0c 或者前端提交的参数和后台需要的参数个数不匹配 xff0c 导致无法封装 xff0c 报错400 解决方法 xff1a 仔细对照前后端字段类型 xff0
  • Ubuntu终端文件管理工具ranger

    一 xff0c 安装 xff1a ubuntu使用apt get 安装 sudo apt get install ranger 二 xff0c 使用 ranger ranger 中有按键和命令两种操作方式 xff0c 按键是直接键入键盘上的
  • C# list根据字段生成排名

    需求分析 xff0c 我们要根据一个变量来生成排名 xff0c 变量数值相同则在同一名 xff0c 名数则跳过 xff0c 比如第一有两个 xff0c 那就不会有第二名 xff0c 直接到第三名 直接上代码 span class token
  • .net 6 web api项目添加日志(Serilog)管理,将日志输出到控制台、文件、数据库

    1 在nuget安装下面几个包 Serilog Serilog AspNetCore 用于日志输出到控制台 Serilog Formatting Compact 用于日志输出到mysql数据库 Serilog Sinks MySQL 用于日
  • GDB调试-新手笔记3

    ldd命令 43 readelf ldd 在制作自己的发行版时经常需要判断某条命令需要哪些共享库文件的支持 xff0c 以确保指定的命令在独立的系统内可以可靠的运行 ldd stack0 可以找到stack0程序使用的共享库 xff0c l
  • Spring源码分析(一)Spring的环境搭建与架构

    目录 一 Spring的基本信息1 1 Spring 概述1 2 架构 二 环境搭建2 1 gradle的安装与配置2 2 Spring源码构建 本图 xff1a 川西旅游中拍摄的 xff08 业余摄影 xff09 官网 xff1a Hom
  • RNA-seq:转录组数据分析处理(上)

    RNA seq xff1a 转录组数据分析处理 xff08 上 xff09 目录 RNA seq xff1a 转录组数据分析处理 xff08 上 xff09 一 流程概括二 准备工作1 fastq测序文件2 注释文件和基因组文件的获取 三
  • STM32串口数据接收 --环形缓冲区

    STM32串口数据接收 环形缓冲区 环形缓冲区简介 在单片机中串口通信是我们使用最频繁的 xff0c 使用串口通信就会用到串口的数据接收与发送 xff0c 环形缓冲区方式接收数据可以更好的保证数据丢帧率第 在通信程序中 xff0c 经常使用
  • Linux下驱动开发

    Linux下驱动开发 1 简介 驱动 xff0c 是指驱动计算机里软件的程序 驱动程序全称设备驱动程序 xff0c 是添加到操作系统中的特殊程序 xff0c 其中包含有关硬件设备的信息 驱动程序是操作系统与硬件连接的桥梁 设备驱动最通俗的解
  • openstack单网卡使用多IP说明、openstack虚拟机IP通网关但同网段IP不互通处理方法

    文章目录 openstack虚拟机IP通网关但同网段IP不互通处理方法问题描述处理方法 Openstack中单网卡使用多ip openstack虚拟机IP通网关但同网段IP不互通处理方法 问题描述 云平台的防火墙虚拟机部署再我们云平台上 x
  • Collections.singletonList使用方法

    方法注释 应用 xff1a 这个方法主要用于只有一个元素的优化 xff0c 减少内存分配 xff0c 无需分配额外的内存 xff0c 可以从SingletonList内部类看得出来 由于只有一个element 因此可以做到内存分配最小化 x
  • 如何修改电脑的MAC地址(手把手更改)

    打开控制面板 xff0c 显示如下 xff0c 然后点击 网络和Internet xff08 windows 43 r xff0c 然后输入control xff0c 按下回车 xff0c 即可打开控制面板 xff09 点击完 网络和Int
  • evo的快速安装Ubuntu 18.04

    由于一键安装成功后打开轨迹后报错 xff1a ERROR evo module evo main traj crashed no logfile written disabled 不会解决 xff0c 索性直接用源码安装方式 xff1a 如
  • 基于 SpringBoot + Vue 的音乐网站系统(源代码+数据库+思路文档)

    一 系统介绍 本项目分为管理员与普通用户两种角色 管理员角色包含以下功能 xff1a 后台对用户 歌曲 歌手 歌单信息的管理 用户角色包含以下功能 xff1a 音乐播放用户登录注册用户信息编辑 头像修改歌单打分歌单 歌曲评论歌单列表 歌手列
  • Linux下PS1设置

    PS1简介 PS1命令是linux系统中的一个全局变量 xff0c 用于定义用户命令行的字符显示 学名为 xff1a 默认提示符 盲猜Power Shell 1 PS1变量 span class token comment shell查看变
  • Linux内存管理

    Linux中的程序都是在进程中执行的 xff0c 而每个进程都有自己的虚拟地址空间 xff0c 进程中的内存操作 xff0c 比如访问 xff0c 插入数据都是在这块虚拟地址空间上操作的 虚拟地址空间 虚拟地址空间是一个进程所使用的虚拟内存
  • Maven库打包解决方案:No plugin found for prefix ‘install’ in the current project and in the plgin groups

    问题描述 我的外部本地包 xff0c 需要打包到我的maven库里 然后报错如下 No plugin found for prefix install in the current project and in the plgin grou
  • Ant Design Blazor表格高度自适应

    Ant Design Blazor表格高度自适应 一 先导入js 在 Host cshtml导入js lt component type 61 34 typeof App 34 render mode 61 34 ServerPrerend
  • Gson临时文件被删除造成的stackOverflowError

    错误内容 今天使用Gson序列化的时候出现了stackOverflowError的错误 xff0c 内容如下 xff1a at span class token class name span class token namespace c