REST API 无限循环

Posted

技术标签:

【中文标题】REST API 无限循环【英文标题】:REST API Infinite loop 【发布时间】:2022-01-07 14:23:50 【问题描述】:

我的 API 显示地址字段的无限循环

当我插入@JsonIgnore、@JsonManagedReference 或@JsonBackReference 我可以清楚地看到一个结果,但我没有嵌套的地址字段。

我应该怎么做才能使地址字段也只有一个结果?

这些是我的主要实体:

1.属性

package com.realestate.petfriendly.entity;

import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import java.io.Serializable;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Data;

@Entity
@Data
@Table(name = "property")
public class Property 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_property")
    private int id_property;
    @Column(name = "title")
    private String title;
    @Column(name = "type")
    private String type;
    @Column(name = "room")
    private String room;
    @Column(name = "price")
    private double price;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "address_id_address")
//  @JsonBackReference
    private Address address;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id_user")
//  @JsonBackReference
    private User user;

 
    用户
package com.realestate.petfriendly.entity;

import com.fasterxml.jackson.annotation.JsonManagedReference;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
@Table(name = "user")
class User 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_user")
    private int id_user;
    @Column(name = "username")
    private String username;
    @Column(name = "name")
    private String name;
    @Column(name = "lastname")
    private String lastname;
    @Column(name = "phone")
    private String phone;
    @Column(name = "notes")
    private String notes;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "user_address_id_user_address")
//  @JsonManagedReference
    private UserAddress userAddress;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
//  @JsonManagedReference
    private List<Property> property = new ArrayList<>();


    地址
package com.realestate.petfriendly.entity;

import com.fasterxml.jackson.annotation.JsonManagedReference;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
@Table(name="address")
class Address

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_address")
    private int id_address;
    @Column(name = "city")
    private String city;
    @Column(name = "municipality")
    private String municipality;
    @Column(name = "place")
    private String place;
    @Column(name = "street")
    private String street;
    @Column(name = "house_number")
    private double house_number;
    
    @OneToOne(mappedBy = "address")
//  @JsonManagedReference
    private Property property;
 

【问题讨论】:

这能回答你的问题吗? Infinite Recursion with Jackson JSON and Hibernate JPA issue @M.Dudek 谢谢。我已经看到了这个并使用了 JsonManaged 和反向引用,但我没有意识到我应该在同一个实体中使用它们。相反,我将一个引用放在一个实体中,另一个放在相关实体中,并像 OneToMany 和 ManyToOne 关系一样使用它们:D 【参考方案1】:

实际上,您的代码中有问题的解决方案,但关键注释被注释掉并且在错误的位置(根据您的要求)。解决此问题的方法之一是使用@JsonManagedReference@JsonBackReference,如下所示:

@Entity
@Data
@Table(name = "property")
public class Property 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_property")
    private int id_property;
    @Column(name = "title")
    private String title;
    @Column(name = "type")
    private String type;
    @Column(name = "room")
    private String room;
    @Column(name = "price")
    private double price;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "address_id_address")
    @JsonManagedReference
    private Address address;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id_user")
    @JsonBackReference
    private User user;

@Entity
@Getter
@Setter
@Table(name = "user")
class User 

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_user")
    private int id_user;
    @Column(name = "username")
    private String username;
    @Column(name = "name")
    private String name;
    @Column(name = "lastname")
    private String lastname;
    @Column(name = "phone")
    private String phone;
    @Column(name = "notes")
    private String notes;

    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "user_address_id_user_address")
    private UserAddress userAddress;

    @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
    @JsonManagedReference
    private List<Property> property = new ArrayList<>();

@Entity
@Getter
@Setter
@Table(name="address")
class Address

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_address")
    private int id_address;
    @Column(name = "city")
    private String city;
    @Column(name = "municipality")
    private String municipality;
    @Column(name = "place")
    private String place;
    @Column(name = "street")
    private String street;
    @Column(name = "house_number")
    private double house_number;
    
    @OneToOne(mappedBy = "address")
    @JsonBackReference
    private Property property;

请记住以下几点:

@JsonManagedReference 是关系的前向部分:正常序列化的部分。 @JsonBackReference 是关系的后面部分:它将从序列化中省略。

如果想对后面的部分有引用关系,可以使用@JsonIdentityInfo,如下:

@Entity
@Data
@Table(name = "property")
@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id_property")
public class Property 
   (...)

@Entity
@Getter
@Setter
@Table(name = "user")
@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id_user")
class User 
   (...)

@Entity
@Getter
@Setter
@Table(name="address")
@JsonIdentityInfo(
  generator = ObjectIdGenerators.PropertyGenerator.class, 
  property = "id_address")
class Address
   (...)

您可以在以下在线资源中阅读有关这些和其他技术的更多信息:https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion。

【讨论】:

非常感谢。这真的对我有帮助。我没有意识到我应该在同一个实体中使用它们。我把它们就像 OneToMany 和 ManyToOne 关系一样——一个引用在一个实体中,另一个在另一个实体中。现在我明白了:D 太棒了!如果我的回答帮助您考虑支持它甚至接受它作为答案,以便它可以“关闭”并且其他人可以从中受益并轻松理解这可能是类似问题的可能解决方案;)谢谢! 当然。完成了:)【参考方案2】:

您在 Property 和 Address 类之间存在循环依赖关系。为了阻止无限的 JSON 序列化循环,您可以在相关属性的一侧添加 @JsonIgnore 注释

【讨论】:

以上是关于REST API 无限循环的主要内容,如果未能解决你的问题,请参考以下文章

自定义 Spring Security 应用程序中的无限循环

从 api 获取时反应 useEffect 无限循环

onetomany / manytoone 的无限循环?春天/休息api

发出 Axios GET 请求时出现无限循环 - 循环不会关闭

从 api 推送数组数据会导致无限循环

在自定义 WebAPi 中调用 Azure Speech API 时进入无限循环