【问题标题】:Infinite Recursion error with Many to One relationship具有多对一关系的无限递归错误
【发布时间】:2020-05-25 09:31:48
【问题描述】:

所以我们在尝试设置数据库时多次遇到这个问题。基本上,我们有一个联赛,除此之外还有多场比赛。每当我们尝试打印出http://localhost:8080/api/leagues 时,页面都会填充我们联赛的无限列表,然后我们就会收到此错误。

"Cannot render error page for request [/api/leagues]和异常[Could not write JSON: Infinite recursion (StackOverflowError);嵌套异常是com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)(通过参考链:org.hibernate.collection.internal.PersistentBag[0]->com.dontfeed.Dont.Feed.model.League["teams"]->org.hibernate.collection.internal.PersistentBag[0]->com .dontfeed.Dont.Feed.model.Team["leagues"]-"

有人知道我们如何解决这个问题吗? @JsonIgnoreProperties 在那里,因为我试图排除故障。我可以把它拿出来。

import com.dontfeed.Dont.Feed.model.enumerator.LeagueFormat;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import javax.validation.constraints.NotNull;

import java.time.LocalDate;
import java.util.List;

@Data
@Entity
@NoArgsConstructor
@Table(name = "leagues")
public class League {

    @Id
    @NotNull
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private long id;

    private LocalDate dateCreated;

    private int duration;

    private LocalDate endDate;

    @Enumerated(EnumType.STRING)
    private LeagueFormat format;

    private String logo;

    private String matchFrequency;

    private int maxTeams;

    @Column(unique = true)
    private String name;

    private String description;

    private LocalDate startDate;

    private String passcode;

    // Relationships
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @OneToOne(fetch = FetchType.LAZY)
    private Game game;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @OneToOne(fetch = FetchType.LAZY)
    private Tournament tournament;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @OneToMany(fetch = FetchType.LAZY)
    private List<Match> matches;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @ManyToMany(mappedBy = "leagues", fetch = FetchType.LAZY)
    private List<Team> teams;

    @Override
    public String toString() {
        return "League{" +
                "id=" + id +
                ", dateCreated=" + dateCreated +
                ", duration=" + duration +
                ", endDate=" + endDate +
                ", format=" + format +
                ", logo='" + logo + '\'' +
                ", matchFrequency='" + matchFrequency + '\'' +
                ", maxTeams=" + maxTeams +
                ", name='" + name + '\'' +
                ", startDate=" + startDate +
                ", description= " + description +
                '}';
    }
}
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import javax.validation.constraints.NotNull;

import java.time.LocalDate;
import java.util.List;

@Data
@Entity
@NoArgsConstructor
@Table(name = "matches")
public class Match {

    @Id
    @NotNull
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", updatable = false, nullable = false)
    private long id;

    private float duration;

    private LocalDate matchDate;

    private long matchId;

    private String score;

    // Relationships
    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @ManyToOne(fetch = FetchType.LAZY)
    private Game game;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @ManyToOne(fetch = FetchType.LAZY)
    private League league;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @ManyToOne(fetch = FetchType.LAZY)
    private Team team_a;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @ManyToOne(fetch = FetchType.LAZY)
    private Team team_b;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @ManyToOne(fetch = FetchType.LAZY)
    private Team victor;

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    @ManyToOne(fetch = FetchType.LAZY)
    private Tournament tournament;

    @Override
    public String toString() {
        return "Match{" +
                "id=" + id +
                ", duration=" + duration +
                ", matchDate=" + matchDate +
                ", matchId=" + matchId +
                ", score='" + score + '\'' +
                ", victor=" + victor +
                '}';
    }
}
import com.dontfeed.Dont.Feed.model.League;
import com.dontfeed.Dont.Feed.service.LeagueService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@AllArgsConstructor
@CrossOrigin(origins = "http://localhost:3000")
@RequestMapping(value = LeagueController.PATH, produces = MediaType.APPLICATION_JSON_VALUE)
public class LeagueController {

    static final String PATH = "/api/leagues";
    private final LeagueService leagueService;

    @GetMapping
    public ResponseEntity<?> getLeagues() {
        System.out.println("Test");
        if (leagueService.findAllLeagues() == null) {
            return ResponseEntity
                    .status(HttpStatus.BAD_REQUEST)
                    .body("No results found");
        }
        return ResponseEntity
                .status(HttpStatus.OK)
                .body(leagueService.findAllLeagues());
    }

【问题讨论】:

标签: java json spring hibernate recursion


【解决方案1】:

从错误看来,您已将 Team 映射到 League 内,并将 League 映射到 Team 内。 它开始转换为 JSON 的周期。

Team 内使用@JsonIgnoreLeague

【讨论】:

  • 我想我对何时使用 JsonIgnore 感到困惑。我需要一个 JsonIgnore 用于 League 内的 Team 吗?我的其他关系呢?我将 JsonIgnore 扔到几乎每个有关系的值上,很明显,当我打电话时,我只会得到那些没有关系的值。因此,如果我将 JsonIgnore 放在 Team 内的 League 中,并且想要调用包含所有联赛的特定 Team,我该怎么做?
  • 对此场景的一个建议 - 使用 DTO 类并避免直接从 API 传递实体。根据需要控制 DTO 行为。例如 - 在联赛 api 上返回与球队的联赛,但不是与联赛的球队。 on team api - 返回与联盟的团队,而不是与团队的联盟。
【解决方案2】:

您必须在不想被反序列化的字段中使用@JsonIgnore 而不是@JsonIgnoreProerties。

如果您想使用@JsonIgnoreProperties,您必须注释类,而不是属性,并在该类中包含您不想反序列化的属性列表。

您可以在此处查看如何使用这些注释:

https://www.concretepage.com/jackson-api/jackson-jsonignore-jsonignoreproperties-and-jsonignoretype

【讨论】:

  • 我想我对何时使用 JsonIgnore 感到困惑。我需要一个 JsonIgnore 用于 League 内的 Team 吗?我的其他关系呢?我将 JsonIgnore 扔到几乎每个有关系的值上,很明显,当我打电话时,我只会得到那些没有关系的值。因此,如果我将 JsonIgnore 放在 Team 内的 League 中,并且想要调用包含所有联赛的特定 Team,我该怎么做?
  • 你必须使用 jsonIgnore 来防止无限递归,我的意思是,如果你想在查询球队时检索联赛,你必须在联赛内的 Team 对象中使用 jsonIgnore,这样球队就会带来联赛,但联赛不会再带来球队
猜你喜欢
  • 2019-09-12
  • 2020-07-25
  • 2020-11-01
  • 2020-05-09
  • 1970-01-01
  • 1970-01-01
  • 2017-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多