infinite.c

 
在Spring Boot应用中,当使用Jackson库将对象序列化为JSON格式返回给客户端时,可能会遇到`HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError)`异常。该异常通常发生在对象之间存在循环引用的情况下,导致Jackson在序列化过程中不断递归,最终超出栈容量而抛出`StackOverflowError`[^1]。 ### 异常原因分析 此类问题的核心在于对象之间的**双向关联**。例如,在一个博客系统中,`Blog`类可能包含一个`Type`类型的属性,而`Type`类又包含一个`List<Blog>`类型的属性。这种情况下,Jackson在序列化`Blog`对象时会尝试序列化其关联的`Type`对象,而该`Type`对象又会反向引用回`Blog`对象,从而形成一个无限递归的循环。这种循环最终导致栈溢出错误[^2]。 ### 解决方案 #### 1. 使用 `@JsonManagedReference` 和 `@JsonBackReference` 这是Jackson提供的用于处理父子关系的注解。`@JsonManagedReference`用于父类的引用,`@JsonBackReference`用于子类的反向引用。这样可以避免在序列化时进入无限递归。 ```java @Entity public class Blog { @ManyToOne @JsonManagedReference private Type type; // 其他字段和方法 } @Entity public class Type { @OneToMany(mappedBy = "type") @JsonBackReference private List<Blog> blogs; // 其他字段和方法 } ``` #### 2. 使用 `@JsonIgnore` 如果某个字段不需要在JSON中暴露,可以使用`@JsonIgnore`注解来忽略该字段的序列化和反序列化过程。这种方式适用于不需要返回的字段,或者字段的引用关系无法通过其他方式解决的情况。 ```java @Entity public class Type { @OneToMany(mappedBy = "type") @JsonIgnore private List<Blog> blogs; // 其他字段和方法 } ``` #### 3. 使用 `@JsonIdentityInfo` `@JsonIdentityInfo`是Jackson提供的另一种解决方案,它通过为每个对象分配一个唯一标识符(ID)来避免重复序列化相同的对象。适用于对象之间存在复杂循环引用的情况。 ```java @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Entity public class Blog { private Long id; @ManyToOne private Type type; // 其他字段和方法 } @JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id") @Entity public class Type { private Long id; @OneToMany(mappedBy = "type") private List<Blog> blogs; // 其他字段和方法 } ``` #### 4. 自定义DTO(Data Transfer Object) 如果对象之间的关系非常复杂,或者需要对返回的JSON结构进行更精细的控制,可以考虑使用DTO模式。即创建一个新的类,仅包含需要返回的字段,并在服务层将实体类转换为DTO类后再进行序列化。 ```java public class BlogDTO { private String title; private String content; private String typeName; public BlogDTO(Blog blog) { this.title = blog.getTitle(); this.content = blog.getContent(); this.typeName = blog.getType().getName(); } } ``` 在控制器中返回`BlogDTO`对象即可避免循环引用问题。 #### 5. 配置Jackson全局忽略循环引用 可以通过配置Jackson的`ObjectMapper`来全局忽略循环引用问题,但这种方式可能会导致某些字段无法正确序列化,因此建议仅在调试或测试环境中使用。 ```java @Configuration public class JacksonConfig { @Bean public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() { return new Jackson2ObjectMapperBuilder() .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .featuresToEnable(SerializationFeature.INDENT_OUTPUT) .featuresToEnable(SerializationFeature.USE_EQUALS_HASHCODE_FOR_ID) .featuresToEnable(SerializationFeature.USE_WRAPPER_ARRAY_FOR_SINGLE_ELEMENT_ARRAYS) .featuresToEnable(SerializationFeature.ORDER_MAP_ENTRIES_BY_KEYS) .featuresToEnable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .featuresToEnable(SerializationFeature.FAIL_ON_EMPTY_BEANS); } } ``` ### 总结 `HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError)`通常由对象之间的循环引用引起。解决方法包括使用Jackson提供的注解(如`@JsonManagedReference`、`@JsonBackReference`、`@JsonIgnore`、`@JsonIdentityInfo`),使用DTO模式,或配置全局的Jackson设置。选择合适的解决方案取决于具体的业务需求和对象结构的复杂性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值