I have two entities, which are in a many to many relationship.
@Entity
public class Room {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @ManyToMany(mappedBy = "rooms")
    private Set<Team> teams;
}
@Entity
public class Team {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    @ManyToMany
    @JoinTable(name = "teams_rooms",
        joinColumns = @JoinColumn(name= "team_id"),
        inverseJoinColumns = @JoinColumn(name = "room_id"))
    private Set<Room> rooms;
}
To yield data, i have a repository for "Room" and "Team":
public interface RoomRepository extends CrudRepository<Room, Long> {
}
public interface TeamRepository extends CrudRepository<Team, Long> {
}
My goal is to request all rooms of a team, but prevent JPA from looping infinitely.
@RestController
@RequestMapping("....")
public class RoomController {
    @Autowired
    private RoomRepository roomRepository;
    
    @GetMapping
    public Iterable<Room> getAllRoomsOfTeam() {
        final long exampleId = 1; //This is just a placeholder. The id will be passed as a parameter.
        
        final var team = teamRepository.findById(exampleId);
        return ResponseEntity.ok(team);
    }
}
This is the result:
{
    "id": 1,
    "name": "Team1",
    "rooms": [
        {
            "id": 1,
            "name": "Room 1",
            "teams": [
                {
                    "id": 1,
                    "name": "Team 1",
                    "rooms": [
                        {
                            "id": 1,
                            "name": "Room 1",
                            "teams": [
Jackson will loop forever, until an exception occurs (Since the back reference also references the parent element, which will create a loop).
I already tried @JsonManagedReference and @JsonBackReference, but they are used for many to one relationships.
How do i stop Jackson from looping infinitely? I want to affect other repositories and queries as little as possible.
Your controller shoud not return entities ( classes with the annotation @Entity). As a best practice is to create another separate class with same attributes. This code has a little dupplication but it keeps all the layers clean. I also suggest to use @Service.
   public class RoomDTO { 
       private String name;
       private List<TeamDTO> teams = new ArrayList<>();   
       public RoomDTO() { 
       }
        
       public RoomDTO(Room room) {
            this.name = room.name;
            for(Team team : room.getTeams()) {
                 TeamDTO teamDTO = new TeamDTO();
                 teamDTO.setName(team.getName);
                 teams.add(teamDTO);
            }
        }
   }
   public class TeamDTO { 
       List<RoomDTO> rooms = new ArrayList();
       public TeamDTO() {
       }
       public TeamDTO(Team team) {
            this.name = team.name;
            for(Room room : team.getRooms()) {
                 RoomDTO roomDTO = new RoomDTO();
                 roomDTO.setName(team.getName);
                 rooms.add(roomDTO);
            }
        }
        
   }
The controller should return this
@GetMapping
public Iterable<TeamDTO> getAllRoomsOfTeam() {
final long exampleId = 1;
final var team = teamRepository.findById(exampleId);
TeamDTO teamDTO = new TeamDTO(team);
return ResponseEntity.ok(teamDTO);
}
How to use DTOs in the Controller, Service and Repository pattern
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With