You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:25:33