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

请求作用域Bean使用ObjectMapper转JSON报无限递归异常如何解决

问题根因

Spring的@RequestScope Bean默认会通过CGLIB生成动态代理对象,你实际注入使用的planInfo不是你定义的PlanInfo类的原生实例,是代理子类的实例。代理对象内部会携带类加载器、Spring上下文相关的属性,这些属性之间存在循环引用,Jackson序列化时就会触发无限递归导致栈溢出,和你自定义的PlanInfo类字段没有关系。

解决方案

你可以根据业务场景选择以下任意一种方案:

  • 方案1(最推荐):抽取独立DTO做序列化
    不要直接将Spring托管的Bean作为数据传输对象序列化,单独定义一个PlanInfoDTO类,属性和PlanInfo保持一致,先将planInfo的属性拷贝到DTO实例后再序列化,既符合分层设计规范,也完全规避代理对象的问题。
    代码示例:
    PlanInfoDTO dto = new PlanInfoDTO();
    // 可以用Spring BeanUtils、MapStruct等工具做属性拷贝
    BeanUtils.copyProperties(planInfo, dto);
    String json = new ObjectMapper().writeValueAsString(dto);
    
  • 方案2:先获取代理的原始目标对象再序列化
    借助Spring的AOP工具类获取代理对应的原生PlanInfo实例,再序列化原生对象即可:
    PlanInfo nativePlanInfo = (PlanInfo) AopProxyUtils.getSingletonTarget(planInfo);
    String json = new ObjectMapper().writeValueAsString(nativePlanInfo);
    
  • 方案3:配置Jackson忽略代理类的特殊属性
    给PlanInfo类加上@JsonIgnoreProperties注解,直接忽略掉代理类携带的Spring内部属性,避免序列化到这些循环引用的字段:
    @Data
    @Component
    @RequestScope
    @JsonIgnoreProperties(value = {"targetSource", "advisors", "beanFactory", "classLoader", "module"}, ignoreUnknown = true)
    public class PlanInfo {
      // 原有字段不变
    }
    
    也可以全局配置ObjectMapper,添加对Spring代理对象的序列化支持:
    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new SpringWebModule());
    mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
    String json = mapper.writeValueAsString(planInfo);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 03:39:01