You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot接口JSON无限递归导致Gson解析MalformedJsonException报错

问题根因
  • 核心故障出在SpringBoot服务端的JSON序列化阶段,和客户端Gson反序列化逻辑无关。你在调试时观察到的PowWowControllerDTO业务层数据填充正常是事实,但SpringBoot默认使用Jackson将返回对象序列化为JSON响应时,出现了双向关联无限递归导致栈溢出的问题。
  • 故障触发逻辑:你的返回DTO中直接嵌套了JPA持久化实体类(带@Entity注解的PowWowJournalHeaderEntity、PowWowTransactionEntity等),这类实体因为表关联映射,普遍存在双向引用关系(例如A实体通过@OneToMany持有B实体集合,B实体又通过@ManyToOne反向持有A实体引用)。Jackson序列化时会沿着对象引用递归遍历,遇到双向引用就会循环访问A→B→A→B……直到触发栈溢出,序列化过程直接中断。
  • 客户端报错的直接原因:序列化中途崩溃后,返回给客户端的是半截不完整的非法JSON:既没有闭合的对象/数组括号,还混入了框架抛出的异常片段(就是你看到的Infinite recursion (StackOverflowError)提示和大量空对象)。Gson解析这种结构残缺的JSON时,自然会抛出MalformedJsonException: Expected EOF的错误。
  • 额外注意:你在接口代码里写的try-catch块根本捕获不到这个序列化异常——因为异常发生在return语句执行之后、SpringBoot调用Jackson序列化响应的阶段,不在你try块的业务代码执行范围内,所以你在catch里设置错误状态的逻辑对这个故障完全不生效。
修复方案
  • 长期最优方案:禁止直接将JPA实体类作为接口返回值嵌套在DTO中。单独定义和接口返回结构匹配的VO(视图对象)类,仅保留前端/调用方需要的字段,通过Bean拷贝工具或者手动赋值的方式,将实体类的对应属性填充到VO中,从根源上切断实体双向关联的序列化路径。
    对应改造示例:
    // 替换原来直接存放实体的写法,新建专用返回VO
    public class PowWowJournalEntities {
        // 替换原PowWowJournalHeaderEntity类型的实体字段
        private PowWowJournalHeaderVO journalHeader;
        private List<PowWowTransactionVO> transactions;
        private List<PowWowAuditTrailVO> auditTrails;
        private PowWowJournalEntryObjectVO entryObject;
    }
    
    VO类中不要保留任何实体间双向关联的反向引用字段,从结构上避免循环遍历的可能。
  • 临时快速修复方案:如果暂时没有精力重构VO层,可以通过Jackson注解打破循环引用:
    • 对不需要返回给调用方的反向引用字段,直接加@JsonIgnore注解,标记序列化时忽略该字段
    • 对需要保留关联数据的双向字段,配对使用@JsonManagedReference(标注在一对多的持有集合侧,即“一”端)和@JsonBackReference(标注在多对一的反向引用侧,即“多”端),让Jackson识别双向关系避免递归。
      注意:这种方案耦合了持久化层和接口层,后续调整实体映射关系时很容易再次触发序列化故障,仅适合临时应急。
  • 补全异常处理逻辑:新增SpringBoot全局异常处理器,捕获JsonMappingException等序列化阶段抛出的异常,统一返回结构完整、格式合法的错误响应,避免再返回半截无效JSON。
  • 修复验证:改完后先直接调用接口,确认返回的JSON结构完整、无栈溢出错误提示,再用旧Struts客户端调用,Gson即可正常完成反序列化。

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 11:36:19