api 요청하면 StackOverFlowError를 뱉어냄
객체를 호출할 때 해당 객체와 참조 관계에 있는 객체와 무한 순환 참조에 걸려서 그렇다고 한다. 잠 시 만 근데 처음에 객체들 맵핑할 때도 관련 문제가 발생해서 연관관계가 있는 부분들에 @JsonIgnore 애노테이션을 넣어서 해결했다.
@Entity
@Table(name = "users")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name ="user_no")
private Long id;
@Column(name = "user_id")
private String userId;
private String username;
public void setPassword(String password) {
this.password = password;
}
private String nickname;
private String password;
private String email;
private String phone;
private String address;
@Builder
public User(String userId, String username, String nickname, String password, String email, String phone, String address) {
this.userId = userId;
this.username = username;
this.nickname = nickname;
this.password = password;
this.email = email;
this.phone = phone;
this.address = address;
}
public void updateNickname(String nickname){ this.nickname = nickname;}
public void updatePassword(String password){ this.password = password;}
public void updateEmail(String email){ this.email = email;}
public void updatePhone(String nickname){ this.phone = phone;}
public void updateAddress(String address){ this.address = address;}
@JsonIgnore
@OneToMany(mappedBy = "user")
private List<Meeting> meetingList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
private List<PhotoList> photoList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
private List<Marker> markerList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
private List<BeforeList> beforeLists = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
private List<ChatText> chatTextsList = new ArrayList<>();
이런 식으로 대부분 관련 처리를 해뒀었다. 그래서 뭐가 문제일까 싶어서 검색을 해봤더니.. @Data를 사용한 경우 @Data에 포함된 @toString 때문이라고 한다. 하지만.. 난 toString을 부르는 곳이 없다고 생각했는데? 싶어 계속 검색을 했다. 하다 보니 나처럼 커스텀필터를 만든 사람이 doFilterInternal 메소드를 실행할 때 같은 문제가 발생하는 것을 보고 설마 나도? 하는 마음에 디버깅을 시도해봤다.
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
super.doFilterInternal(request, response, chain);
String JwtHeader = request.getHeader("Authorization");
System.out.println("JwtHeader: " + JwtHeader);
if(JwtHeader == null || !JwtHeader.startsWith("create ")) {
chain.doFilter(request, response);
return;
}
chain.doFilter에 브레이킹 포인트를 걸었다. 관련된 곳들까지 다 보다가 toString을 호출하는 곳을 찾아냈다. proxy객체의 toString을 호출하려고 하니 당연히 무한 순환 참조에 걸릴 수 밖에.. LazyLoading을 걸어놨기 때문에 프록시 객체에 연관관계 객체는 아직 정보가 없다. 그러니 그것을 찾으려고 a에서 b로 b에서 a로 계속 서로 왔다 갔다 하다가 이런 오류가 발생했을 것이다. 근데 왜 authentication toString이 문제가 되는진 모르겠다. 다른 객체도 아니고..? 🧐
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
.addFilter(new JwtAuthenticationFilter(authenticationManager(http.getSharedObject(AuthenticationConfiguration.class))))
.addFilter(new JwtAuthorizationFilter(authenticationManager(http.getSharedObject(AuthenticationConfiguration.class)), userRepository));
//SecurityConfig
http.sessionManagement(httpSecuritySessionManagementConfigurer ->
httpSecuritySessionManagementConfigurer
.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.httpBasic(b -> b.disable())
.apply(new MyCustomDsl());
----------------------------------------------------------------------------
public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> {
@Override
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
http
.addFilter(new JwtAuthenticationFilter(authenticationManager))
.addFilter(new JwtAuthorizationFilter(authenticationManager, userRepository));
}
}
authentication이 문제가 되고 있었기 때문에 정말 이것저것 다 시도해보았으나 그냥 코드를 원복 시키는 것으로 해결했다.. 내 스스로 Config 파일을 만들고 해결해보려는 시도는 좋았지만.. 시간이 너무 오래 잡아 먹힐 땐 그냥 되는 것으로 해결하기..^^