JPA双向一对多映射添加@Json注解仍触发toString无限循环求助
JPA双向一对多映射toString无限循环栈溢出问题解决
问题背景
使用JPA对接Oracle数据库,为scheme_code_templates与multilingual_template_v2表实现双向一对多、多对一映射。已添加@JsonManagedReference和@JsonBackReference注解解决JSON序列化循环问题,但调用SchemeCodeRepository的findAll()并输出multilingualTemplates时,出现toString无限循环的栈溢出错误。
相关代码与信息
MultilingualTemplateV2 实体类
@Entity @Table(name = "multilingual_template_v2") @Data @AllArgsConstructor @NoArgsConstructor @Builder @ToString public class MultilingualTemplateV2 { @NotNull() String language; @NotNull() @Nationalized String template; @Id @Column(name="template_code") @NotNull() String templateCode; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "associated_schemecode") @JsonManagedReference SchemeCode schemeCode; }
SchemeCode 实体类
@Entity @Table(name = "scheme_code_templates") @Data @AllArgsConstructor @NoArgsConstructor @Builder @ToString public class SchemeCode { @Column(name="associated_pushcode") Integer associatedPushcode; @NotNull String description; @Id @NotNull() String schemeCode; @OneToMany(mappedBy = "schemeCode", cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JsonBackReference List<MultilingualTemplateV2> multilingualTemplates; }
报错栈信息
at org.hibernate.collection.spi.PersistentBag.toString(PersistentBag.java:585) ~[hibernate-core-6.1.7.Final.jar:6.1.7.Final] at java.lang.String.valueOf(String.java:4218) ~[?:?] at java.lang.StringBuilder.append(StringBuilder.java:173) ~[?:?] at com.dcb.smsbatch.dataLayer.entities.SchemeCode.toString(SchemeCode.java:34) ~[classes/:?] at java.lang.String.valueOf(String.java:4218) ~[?:?] at java.lang.StringBuilder.append(StringBuilder.java:173) ~[?:?] at com.dcb.smsbatch.dataLayer.entities.MultilingualTemplateV2.toString(MultilingualTemplateV2.java:30) ~[classes/:?] ...(循环重复的栈信息)
问题原因
Lombok的@ToString注解默认生成包含所有字段的toString方法,包括关联的实体对象。当SchemeCode的toString方法包含multilingualTemplates列表时,列表中的每个MultilingualTemplateV2对象调用toString又会引用SchemeCode对象,形成无限循环调用,最终导致栈溢出。
注意:@JsonManagedReference和@JsonBackReference仅解决JSON序列化时的循环问题,对toString方法的循环引用无效。
解决方案
通过Lombok的注解排除toString中的关联字段,打破循环引用:
方案1:在@ToString注解中指定排除字段
修改两个实体类的@ToString注解,排除引发循环的关联字段:
修改后的MultilingualTemplateV2
@Entity @Table(name = "multilingual_template_v2") @Data @AllArgsConstructor @NoArgsConstructor @Builder @ToString(exclude = "schemeCode") // 排除关联的SchemeCode对象 public class MultilingualTemplateV2 { // 字段与注解不变 }
修改后的SchemeCode
@Entity @Table(name = "scheme_code_templates") @Data @AllArgsConstructor @NoArgsConstructor @Builder @ToString(exclude = "multilingualTemplates") // 排除关联的列表 public class SchemeCode { // 字段与注解不变 }
方案2:使用@ToString.Exclude标记单个字段
在关联字段上直接添加@ToString.Exclude注解,更精准地排除:
MultilingualTemplateV2 修改示例
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "associated_schemecode") @JsonManagedReference @ToString.Exclude // 排除该字段在toString中 SchemeCode schemeCode;
SchemeCode 修改示例
@OneToMany(mappedBy = "schemeCode", cascade = CascadeType.ALL, fetch = FetchType.EAGER) @JsonBackReference @ToString.Exclude // 排除该字段在toString中 List<MultilingualTemplateV2> multilingualTemplates;
验证测试
修改实体类后重新运行测试代码:
for (SchemeCode schemeCode : schemeRepo.findAll()) { System.out.println(schemeCode.getMultilingualTemplates()); }
此时输出multilingualTemplates时,toString方法不会再触发循环调用,避免栈溢出问题。
内容的提问来源于stack exchange,提问作者Shiladitya Thakur
相关产品推荐
相关产品推荐

