请求作用域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内部属性,避免序列化到这些循环引用的字段:
也可以全局配置ObjectMapper,添加对Spring代理对象的序列化支持:@Data @Component @RequestScope @JsonIgnoreProperties(value = {"targetSource", "advisors", "beanFactory", "classLoader", "module"}, ignoreUnknown = true) public class PlanInfo { // 原有字段不变 }ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new SpringWebModule()); mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); String json = mapper.writeValueAsString(planInfo);
内容的提问来源于stack exchange,提问作者Venkat
相关产品推荐
相关产品推荐

