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

Hibernate同一表多关系问题:合并实体后遇JsonMappingException无限递归

Fixing JsonMappingException: Infinite Recursion After Merging Author/Student into Accounts Entity

Ah, I’ve dealt with this exact headache when refactoring entity relationships—let’s break down what’s going on and how to fix it.

Why This Happens

When you merged Author and Student into a single Accounts entity, you created two overlapping relationships with Courses:

  • One-to-Many: An Accounts (ex-Author) creates multiple Courses (via Courses.account_id)
  • Many-to-Many: An Accounts (ex-Student) enrolls in multiple Courses via the Enrollments join table

Jackson hits infinite recursion because it tries to serialize bidirectional references:

  1. When serializing an Accounts, it includes its created Courses
  2. Each Course includes its creator Accounts
  3. That Accounts again includes its created Courses... and the cycle never ends.
    The same loop can happen with the Enrollments <-> Courses <-> Accounts chain too.

Practical Solutions

1. Break the Cycle with @JsonIgnore

The simplest fix is to tell Jackson to ignore one side of the bidirectional reference. Choose which side doesn’t need to show up in your JSON response based on your business needs.

For example, if you don’t need to return the creator Accounts when serializing a Course:

public class Courses {
    private Long id;
    private String name;

    // Ignore this field during serialization to break the loop
    @JsonIgnore
    private Accounts creator;

    private List<Enrollments> enrollments;
    // Getters & Setters
}

Or if you don’t need to return an Accounts's created courses when serializing the account:

public class Accounts {
    private Long id;
    private String username;

    @JsonIgnore
    private List<Courses> createdCourses;

    private List<Enrollments> enrolledCourses;
    // Getters & Setters
}

2. Use @JsonManagedReference & @JsonBackReference

Jackson has built-in annotations for bidirectional relationships to handle serialization properly:

  • @JsonManagedReference: Marks the "forward" side of the relationship (this gets serialized)
  • @JsonBackReference: Marks the "back" side (this gets skipped to avoid loops)

Apply them like this:

// Accounts entity
public class Accounts {
    private Long id;
    private String username;

    // This side gets serialized
    @JsonManagedReference
    private List<Courses> createdCourses;

    private List<Enrollments> enrolledCourses;
    // Getters & Setters
}

// Courses entity
public class Courses {
    private Long id;
    private String name;

    // This side is skipped during serialization
    @JsonBackReference
    private Accounts creator;

    private List<Enrollments> enrollments;
    // Getters & Setters
}

3. Track References with @JsonIdentityInfo

This annotation assigns a unique ID to each entity instance. When Jackson encounters the same instance again, it uses the ID instead of re-serializing the entire object, stopping the loop.

Add it to both your Accounts and Courses entities:

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Accounts {
    private Long id;
    // Other fields & relationships
}

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
public class Courses {
    private Long id;
    // Other fields & relationships
}

4. Use DTOs (Data Transfer Objects)

If you don’t want to modify your entity annotations (or need more control over the JSON output), create DTOs that only include the fields you need, excluding circular references.

For example:

// DTO for Accounts (only includes necessary data)
public class AccountsDTO {
    private Long id;
    private String username;
    private List<CourseSimpleDTO> createdCourses;
    private List<CourseSimpleDTO> enrolledCourses;

    // Convert from Accounts entity to DTO
    public AccountsDTO(Accounts account) {
        this.id = account.getId();
        this.username = account.getUsername();
        // Map created courses to simple DTOs (no creator reference)
        this.createdCourses = account.getCreatedCourses().stream()
            .map(course -> new CourseSimpleDTO(course.getId(), course.getName()))
            .collect(Collectors.toList());
        // Do the same for enrolled courses via Enrollments
    }
}

// Simple DTO for Courses (no circular references)
public class CourseSimpleDTO {
    private Long id;
    private String name;

    public CourseSimpleDTO(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}

Quick Check

Double-check your JPA mappings to make sure the relationships are configured correctly after merging Author and Student—a misconfigured @ManyToOne or @OneToMany can make the recursion issue worse.

内容的提问来源于stack exchange,提问作者nomadus

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 14:23:14