본문 바로가기

Spring Boot

[Jackson] 순환참조 해결방법

728x90

시간표 관리 시스템을 개발하면서 피할 수 없는 Json 순환참조(Circular Reference) 문제가 발생하였다. 즉 직렬화를 하면무한 루프에 빠지게 되는 것.

 

문제점

과목(Subject)와 강의실(Room)은 다대 다(ManyToMany)관계를 갖는데, 서로 참조 관계에 있기 때문에 StackOverflowError가 발생

 

일반적인 해결책

일반적으로 @JsonIgnore를 이용해 해당 필드의 직렬화를 막거나, @JsonManagedReference - @JsonBackReference 쌍을 이용해 단방향으로만 직렬화가 가능하게 한다.

 

또 문제

하지만 우리는 조금 더 특별한 해결책이 필요하다.

순환참조 없이 양방향 직렬화가 필요하기 때문

즉 Subject 하뒤에도 Room 이 필요, Room 하위에도 Subject가 필요한 상황이다.

 

더 좋은 해결책

@JsonIgnoreProperties 어노테이션을 이용하면 직렬화 대상 필드에게 직렬화하지 않을 필드를 지정해 줄 수 있다.

즉 우리가 원하던 양방향 직렬화를 해결할 수 있게 되는 것이다.

 

Subject.java

@Getter
@Setter
@Entity
@Table(name = "subject")
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Subject {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @EqualsAndHashCode.Include
  private Integer id;

  @NotNull
  @Size(min = 2, max = 100)
  private String name;


  @ManyToMany(fetch = FetchType.EAGER)
  @JoinTable(name = "subject_room_mapping", joinColumns = @JoinColumn(name = "subject_id"), inverseJoinColumns = @JoinColumn(name = "room_id"))
  @JsonIgnoreProperties("subjectList")
  private List<Room> roomList = new ArrayList<>();
}

Room.java

@Getter
@Setter
@Entity
@Table(name = "room")
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class Room {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @EqualsAndHashCode.Include
  private Integer id;

  @NotBlank
  @Size(min = 2, max = 50)
  private String name;

  @ManyToMany(fetch = FetchType.EAGER)
  @JoinTable(name = "subject_room_mapping", joinColumns = @JoinColumn(name = "room_id"), inverseJoinColumns = @JoinColumn(name = "subject_id"))
  @JsonIgnoreProperties("roomList")
  private List<Subject> subjectList = new ArrayList<>();
}

 

결과(JSON)

{
	"data": [{
		"id": 1,
		"name": "123",
		"roomList": [{
			"id": 1,
			"name": "321"
		}, {
			"id": 2,
			"name": "456"
		}, {
			"id": 3,
			"name": "852"
		}]
	}],
	"error": null
}
728x90