0

So we have been facing this issue multiple times we try to set up the database. Basically we have a league that will have multiple matches apart of it. Whenever we just try to printout http://localhost:8080/api/leagues the page populates with an infinite list of our leagues and then we get this error.

"Cannot render error page for request [/api/leagues] and exception [Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: 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"]-"

Does anyone have any idea on how we can resolve this? The @JsonIgnoreProperties are there because I was trying to troubleshoot. I can take that out.

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());
    }
  • welcome to stackoverflow. Take a tour and get your first badge-https://stackoverflow.com/tour – Hemant May 25 '20 at 09:41
  • Does this answer your question? [Infinite Recursion with Jackson JSON and Hibernate JPA issue](https://stackoverflow.com/questions/3325387/infinite-recursion-with-jackson-json-and-hibernate-jpa-issue) – Michał Krzywański May 25 '20 at 09:49

2 Answers2

0

You must use @JsonIgnore instead @JsonIgnoreProerties in the fields you want to not be deserialized.

If you want to use @JsonIgnoreProperties you must annotate the class, not the property and include the list of the properties in that class that you dont want to deserialize.

You can view how to use those annotations here:

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

JArgente
  • 2,239
  • 1
  • 9
  • 11
  • I guess I am confused on when to use JsonIgnore. Would I need a JsonIgnore for Team inside League? What aboure my other relationships? I threw JsonIgnore on literally every value that has a relationship and clearly when I make a call I only get the ones that don't have it. So if I put JsonIgnore on League inside Team and want to call a specific Team with all the leagues they are in, how would I do that? – ArmyyStrongg May 29 '20 at 08:14
  • You have to use jsonIgnore to prevent an infinite recursion, I mean if you want to retrieve the league when you query for a Team you have to use jsonIgnore in the Team object inside the league so the team will bring the league but the league wont bring the Team again – JArgente May 29 '20 at 08:19
0

From error it seems that you have mapped Team inside League and League inside Team. It starts cycle of conversion to JSON.

Use @JsonIgnore with League inside Team.

Hemant
  • 1,403
  • 2
  • 11
  • 21
  • I guess I am confused on when to use JsonIgnore. Would I need a JsonIgnore for Team inside League? What aboure my other relationships? I threw JsonIgnore on literally every value that has a relationship and clearly when I make a call I only get the ones that don't have it. So if I put JsonIgnore on League inside Team and want to call a specific Team with all the leagues they are in, how would I do that? – ArmyyStrongg May 29 '20 at 08:11
  • one suggestion for this scenario - Use DTO classes and avoid passing entities directly from API. control DTO behaviour as per need. for example - on league api return league with team but not team with league. on team api - return team with league and not league with team. – Hemant May 29 '20 at 09:04