Jackson & Constructor
프로젝트를 진행 중에 굉장히 난감한 문제를 겪었다.
문제는 아래와 같다.
// 댓글 다는 DTO
@Data
public class PostCommentReq {
private final Long accountId;
private final String content;
}
// 댓글 수정 DTO
@Data
public class PatchCommentReq {
private final String content;
}
댓글 다는 DTO는 전혀 문제가 없이 잘 작동을 했지만 댓글 수정 DTO는 제대로 된 값을 계속해서 못받아오는 상황,,,!!!
일단 @Data 가 무엇인지 살펴보자!
* Equivalent to {@code @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode}.
@Data를 까보면 위와 같은 주석을 확인할 수 있는데, 해석해보자면
@Data는 @code @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode 와 똑같다 라는 뜻
여기서 생성자와 관련된 곳은 바로 @RequiredArgsConstructor이다.
@RequiredArgsConstructor 이란?
@RequiredArgsConstructor은 초기화 되지 않은 final 필드나, @NotNull 이 붙은 필드에 대해 생성자를 생성해준다.
여기서 알 수 있는 점은 댓글 다는 DTO와 댓글 수정 DTO 모두 final을 붙여주었고 @Data가 @RequiredArgsConstructor을 포함하고 있으니까 인자 있는 생성자가 잘 작동해야한다고 생각했다.
하지만 결과는 댓글 다는 DTO는 인자 있는 생성자가 호출됐지만 댓글 수정 DTO는 인자 있는 생성자를 호출하지 못했다.
이에 대해 몇가지 시도를 해보았는데
- 댓글 수정 DTO의 필드에 final를 빼보았다.
final이 없기 때문에 기본 생성자로 호출이 된 것을 확인할 수 있었다. - 필드를 2개 이상으로 바꿔보았다.
이또한 인자 있는 생성자를 잘 호출하는 것을 확인할 수 있었다.
어떻게 된 것인지 알아보자!!
Jackson
json을 파싱하고 생성하는 라이브러리
내부적으로 Object Mapper class가 있어 json 파일을 파싱해서 자바 객체로 역직렬화 하거나, 자바 객체로부터 json을 직렬화시킬 수 있음
Jackson은 spring web dependency를 추가하면 자동으로 설치
Jackson은 Java Reflection을 사용
What is Java Reflection?
구체적인 클래스 타입을 알지 못해도 그 클래스의 메소드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API
Java Reflection은 생성자의 인자 정보들을 가져올 수 없음
-> 따라서 기본 생성자 없이 파라미터가 있는 생성자만 존재한다면 java Reflection이 객체를 생성할 수 없게 됨
Jackson이 역직렬화를 할 때 반드시 기본 생성자가 필요한 이유였다.
그렇다면 왜 댓글 다는 DTO는 기본 생성자 없이 역직렬화가 가능했을까?
바로 jackson-module-parameter-names 모듈 덕분!
jackson-module-parameter-names 모듈은 기본 생성자가 없는 경우 필드에 데이터를 넣을 수 있는 다른 루트 검색 -> 인자가 있는 생성자로 바인딩
그래서 기본 생성자가 존재하지 않아도 다른 생성자에 역할을 위임해서 객체 바인딩 진행
그렇다면 여기서 또 아니 그래서 인자가 한 개인 생성자는 왜 바인딩이 안되는데!!
인자가 한개면 ObjectMapper가 모듈을 등록해도 역직렬화를 해주지 못한다고 함,,,(이유 아시는 분??ㅎㅎ)
그렇다면 어떻게 역직렬화를 해야할까?
기본생성자를 만들어주거나
@JsonCreator
public dto(String content){
this.content = content;
}
@JsonCreator 을 사용해주면 된다고 한다.
References
https://da-nyee.github.io/posts/woowacourse-why-the-default-constructor-is-needed/
https://beaniejoy.tistory.com/76