JPA双向关联Jackson BeanSerializer.serialize序列化报错排查
Jackson双向关联循环序列化报错修复方案
核心问题根因
你遇到的报错和@JsonManagedReference/@JsonBackReference的value属性配置无关,触发原因有两点:
- 关联字段上同时叠加
@JsonBackReference和@JsonIgnore,两个注解的序列化过滤规则冲突,Jackson会直接跳过循环引用处理逻辑,所有过滤配置完全失效。 - Lombok的
@Data注解默认生成的toString()、equals()、hashCode()方法会包含所有实体字段,双向关联的实体互相调用这些方法时会触发无限递归,异常栈会落到Jackson序列化流程中,极易误导排查方向。
第一步:修正注解配置,移除冲突项
首先删掉所有关联字段上额外添加的@JsonIgnore,保证同一组双向关联只保留一对配对的引用注解,标注位置严格遵循规则:@JsonManagedReference标注在一对多的「一」侧集合字段(序列化时正常输出),@JsonBackReference标注在多对一的「多」侧关联对象字段(序列化时忽略,阻断循环)。
你当前的注解配对方向本身没有错误,清理冲突注解后参考如下配置核对即可:
Auction类核心配置
@Data @Entity public class Auction { // 其他自有字段... @OneToMany(mappedBy = "auction") @JsonManagedReference(value = "selling-item") private List<Bid> bids = new ArrayList<>(); @ManyToOne @JsonBackReference(value = "sell") private User creator; @ManyToOne @JsonBackReference(value = "buyer") private User buyer; }
User类核心配置
@Data @Entity public class User implements UserDetails { // 其他UserDetails接口实现字段、自有字段... @OneToMany(mappedBy = "buyer") @JsonManagedReference(value = "bidder") private List<Bid> bids = new ArrayList<>(); @OneToMany(mappedBy = "creator") @JsonManagedReference(value = "sell") private List<Auction> productsOnSale = new ArrayList<>(); @OneToMany(mappedBy = "buyer") @JsonManagedReference(value = "buyer") private List<Auction> biddedProducts = new ArrayList<>(); }
Bid类核心配置
@Data @Entity public class Bid { // 其他自有字段... @ManyToOne @JsonBackReference(value = "bidder") private User buyer; @ManyToOne @JsonBackReference(value = "selling-item") private Auction auction; }
第二步:修复Lombok @Data导致的隐性循环
不需要移除@Data注解,只要通过Lombok自带注解排除双向关联字段,避免生成的方法触发递归即可:
- 给每个实体类添加
@EqualsAndHashCode(exclude = "当前类持有的所有关联字段名"),例如Auction类就写@EqualsAndHashCode(exclude = {"bids", "creator", "buyer"}) - 给每个实体类添加
@ToString(exclude = "当前类持有的所有关联字段名"),例如Bid类就写@ToString(exclude = {"buyer", "auction"})
更稳定的替代方案(推荐)
如果后续业务需要在序列化Bid、Auction对象时同时返回关联的User信息,@JsonBackReference会直接忽略标注字段,无法满足返回关联数据的需求,可以直接替换为类级别@JsonIdentityInfo注解,不需要手动配对父子引用,配置成本更低,不会出现规则冲突:
在三个实体类的类级别统一添加如下注解即可:
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
该注解会在序列化遇到循环引用时,第二次遇到同一个对象仅输出对象主键id,不会递归序列化整个对象,从根源阻断循环,也不会和Lombok注解冲突。
@JsonIgnore使用说明
- 不需要移除Lombok的
@Data注解,@JsonIgnore直接加在字段上即可生效,Lombok生成的getter/setter不会影响Jackson对字段注解的扫描识别。 - 如果字段上添加
@JsonIgnore不生效,先检查是否同时混用了其他序列化框架(如Fastjson)的注解,不同框架的注解不要叠加使用。 - 禁止在同一个关联字段上同时使用
@JsonIgnore和@JsonManagedReference/@JsonBackReference,规则冲突会导致所有注解失效。
内容的提问来源于stack exchange,提问作者Baris
相关产品推荐
相关产品推荐

