Spring JPA多对多关联引发JSON无限递归问题求解决方案
解决Spring JPA多对多关联的JSON无限递归及字段忽略问题
一、解决无限递归问题
你遇到的无限递归是因为Jackson序列化时,Project和Technology的双向关联会互相引用,导致循环序列化。使用@JsonManagedReference和@JsonBackReference可以明确序列化方向,打破递归:
@JsonManagedReference:标记主动序列化的关联字段,序列化时正常输出该字段内容@JsonBackReference:标记反向关联字段,序列化时忽略该字段,避免递归
修改后的Project类:
package com.example.technologyradar.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import com.fasterxml.jackson.annotation.JsonManagedReference; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Data @AllArgsConstructor @NoArgsConstructor public class Project { @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "native") @GenericGenerator(name="native", strategy = "native") private Long id; private String name; // 添加@JsonManagedReference标记主动序列化的关联 @JsonManagedReference @ManyToMany(mappedBy = "projects") private Set<Technology> assignedTechnologies = new HashSet<Technology>(); }
修改后的Technology类:
package com.example.technologyradar.model; import com.example.technologyradar.dto.constant.TechnologyStatus; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import com.fasterxml.jackson.annotation.JsonBackReference; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.HashSet; import java.util.Set; @Entity @Data @AllArgsConstructor @NoArgsConstructor public class Technology { @Id @GeneratedValue(strategy = GenerationType.AUTO, generator = "native") @GenericGenerator(name="native", strategy = "native") private Long id; private String name; @Enumerated(EnumType.STRING) private TechnologyStatus technologyStatus; @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, targetEntity = Category.class) @JoinColumn(name="category_id", referencedColumnName = "id", nullable = false) private Category category; @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, targetEntity = Coordinate.class) @JoinColumn(name="coordinate_id", referencedColumnName = "id", nullable = false) private Coordinate coordinate; // 添加@JsonBackReference标记反向关联,序列化时忽略 @JsonBackReference @ManyToMany @JoinTable( name = "projects_technologies", joinColumns = @JoinColumn(name="technology_id"), inverseJoinColumns = @JoinColumn(name="project_id") ) private Set<Project> projects = new HashSet<Project>(); }
二、忽略Technology中的Coordinate和Category字段
要在序列化Technology时忽略这两个字段,有两种简单实现方式:
方式1:字段级添加@JsonIgnore
直接在目标字段上添加注解,标记序列化时忽略该字段:
@JsonIgnore @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, targetEntity = Category.class) @JoinColumn(name="category_id", referencedColumnName = "id", nullable = false) private Category category; @JsonIgnore @OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST, targetEntity = Coordinate.class) @JoinColumn(name="coordinate_id", referencedColumnName = "id", nullable = false) private Coordinate coordinate;
方式2:类级添加@JsonIgnoreProperties
在Technology类上指定要忽略的属性集合,更适合批量忽略场景:
@Entity @Data @AllArgsConstructor @NoArgsConstructor @JsonIgnoreProperties({"category", "coordinate"}) // 标记要忽略的属性 public class Technology { // ... 原有代码 }
验证效果
修改完成后,调用getProjectsWithTechnologyUsage()方法时,序列化的JSON会符合预期:
- 每个Project包含id、name,以及对应的assignedTechnologies列表
- 每个Technology仅包含id、name、technologyStatus,不会包含category、coordinate字段,同时彻底解决无限递归问题
内容的提问来源于stack exchange,提问作者Krzysztof Michalski
相关产品推荐
相关产品推荐

