Intro
Spring Repository에서 객체를 조회하는 도중에 아래의 에러가 발생했다.
2022-02-23 10:44:22.914 ERROR 58164 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception
[Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError);
nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError)
(through reference chain: com.devjaewoo.springtest.entity.Client["authorities"]->
org.hibernate.collection.internal.PersistentSet[0]->
com.devjaewoo.springtest.entity.ClientAuthority["client"]->
com.devjaewoo.springtest.entity.Client["authorities"]->
org.hibernate.collection.internal.PersistentSet[0]->
com.devjaewoo.springtest.entity.ClientAuthority["client"]->
com.devjaewoo.springtest.entity.Client["authorities"]->
org.hibernate.collection.internal.PersistentSet[0]->
com.devjaewoo.springtest.entity.ClientAuthority["client"]->
...
com.devjaewoo.springtest.entity.Client["authorities"]->
org.hibernate.collection.internal.PersistentSet[0]->
com.devjaewoo.springtest.entity.ClientAuthority["client"]->
com.devjaewoo.springtest.entity.Client["authorities"])] with root cause
오류를 보면 Client 클래스와 ClientAuthority 클래스를 계속 왔다 갔다 하며 무한 반복되는 것을 볼 수 있다.
현재 Client와 ClientAuthority 클래스는 Many to Many 관계를 표현하기 위해 아래와 같이 구성되어있다.
Client.java
@Entity
@Table(name = "client")
@Getter
@Setter
@Builder
@NoArgsConstructor
public class Client {
...
@OneToMany(mappedBy = "client")
private Set<ClientAuthority> authorities;
...
}
ClientAuthority.java
@Entity
@Table(name = "client_authority")
@Getter
@Setter
@Builder
@NoArgsConstructor
public class ClientAuthority {
...
@ManyToOne
@JoinColumn(name = "client_id")
private Client client;
...
}
에러 발생 원인
코드를 보면 알다시피 Client 클래스에 ClientAuthority 변수가 있고, ClientAuthority에 Client 변수가 있다.
그래서 Jackson 라이브러리에서 Client JSONObject를 만드는 도중 아래의 과정을 무한 반복하는 것이다.
Client 클래스의 getter 조회 -> getAuthorities를 실행해 Set<ClientAuthority> 반환받음 -> 각 ClientAuthority 클래스의 getter 조회 -> getClient를 실행해 Client를 반환 받음 -> Client 클래스의 getter 조회 -> ...
이런 무한반복을 해결하기 위해선 서로 계속 조회하는 굴레를 끊어줘야 하는데,
난 Authority 관련 getter를 별도로 생성해 주는 방식으로 해결했다.
Client.java
public class Client {
...
@JsonIgnore
@OneToMany(mappedBy = "client")
private Set<ClientAuthority> clientAuthorities;
...
}
우선 기존의 authorities 변수를 clientAuthorities로 변경하고, @JsonIgnore 어노테이션을 추가했다.
@JsonIgnore 어노테이션을 추가하면 Jackson에서 JSONObject를 만들 때 해당 변수는 추가하지 않는다.
하지만 authorities 정보는 들어가야 하기 때문에, ClientAuthority가 아닌 Authority를 직접 반환해주는 함수를 별도로 만들었다.
public class Client {
...
@JsonIgnore
@OneToMany(mappedBy = "client")
private Set<ClientAuthority> clientAuthorities;
@JsonProperty("authorities")
public Set<Authority> getAuthorities() {
return clientAuthorities.stream().map(ClientAuthority::getAuthority).collect(Collectors.toSet());
}
...
}
이렇게 수정하면 Jackson에서 Set<ClientAuthority>가 아닌 Set<Authority>를 조회해 계속 서로를 조회하는 일이 없도록 막아준다.
수정 결과
수정 후 다시 해보니 잘 된다.
'Tips > Spring Boot' 카테고리의 다른 글
[Spring Boot] WebSecurityConfigurerAdapter Deprecated 해결하기 (0) | 2022.11.15 |
---|---|
[Spring Boot] Process 'Gradle Test Executor 1' finished with non-zero exit value 1 해결법 (0) | 2022.10.30 |
[Spring Boot] @DataJpaTest에서 JPAQueryFactory Bean 등록 안될때 (0) | 2022.10.27 |
[Spring Boot] OSIV (Open Session In View) 비활성화 후 JPA 조회 안될 때 (0) | 2022.09.21 |
[Spring] 빌드 시 invalid source release: XX 뜰 때 (0) | 2022.08.31 |