admin管理员组

文章数量:1410717

I have a model for Category and Im using an adjacency list structure. When I'm trying to list all categories I'm receiving an infinite recursive loop. How can I fix it?

public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String blob;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "parent_id")
private Category parent;

@OneToMany(
        mappedBy = "parent",
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        fetch = FetchType.EAGER
)
private List<Category> categories;

@OneToMany(mappedBy = "category")
private List<Product> products;

I have a model for Category and Im using an adjacency list structure. When I'm trying to list all categories I'm receiving an infinite recursive loop. How can I fix it?

public class Category {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String blob;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "parent_id")
private Category parent;

@OneToMany(
        mappedBy = "parent",
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        fetch = FetchType.EAGER
)
private List<Category> categories;

@OneToMany(mappedBy = "category")
private List<Product> products;
Share Improve this question asked Mar 5 at 19:59 Andrej VelkovAndrej Velkov 751 silver badge6 bronze badges 1
  • here is an example: i.imgur/fRP8ZUh.png – Andrej Velkov Commented Mar 5 at 20:01
Add a comment  | 

2 Answers 2

Reset to default 1

I thought that your issue is caused by using FetchType.EAGER on both parent and categories, leads to an infinite recursive loop when loading categories.

Solution: Change both relationships to lazy loading:

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Category parent;

@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private List<Category> categories;
  1. Use @JsonIgnore for the Parent Category

The simplest and most effective way is to hide the parent field during serialization. This will break the cycle when converting to JSON.

Fixed Code:

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "parent_id")
@JsonIgnore
private Category parent;

Now, when serializing Category, the parent field will be excluded from the JSON output, preventing infinite recursion.

  1. Use @JsonManagedReference and @JsonBackReference

If you need to serialize both the parent and child categories while avoiding recursion, you can use managed references.

@OneToMany(
        mappedBy = "parent",
        cascade = CascadeType.ALL,
        orphanRemoval = true,
        fetch = FetchType.EAGER
)
@JsonManagedReference
private List<Category> categories;

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "parent_id")
@JsonBackReference
private Category parent;
  • @JsonManagedReference marks the list of child categories as the main side of the relationship.
  • @JsonBackReference marks the parent category so it won’t be serialized again.

Now, when serializing a Category object, it will contain a list of categories, but for each child category, the parent field will be omitted.

  1. Use @JsonIdentityInfo to Serialize IDs Instead of Nested Objects

If you need to serialize both the parent and child categories without duplicating data, you can use object identity references.

@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Entity
public class Category {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "parent_id")
    private Category parent;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
    private List<Category> categories;
}

The parent field now contains a reference by ID instead of a nested object, preventing circular recursion.

本文标签: springRecursive loopsHIBERNATEStack Overflow