내가 DTO에 @Getter, @Setter를 적용했던 이유

Kevin·2024년 3월 18일
1
post-thumbnail

그 때 당시에는 Spring은 물론 Java에 대한 개념도 매우 약할 때라 지금도 약하지만

레퍼런스의 코드를 가져다 사용하기에 급급했다.

당시의 나는 해당 개념에 대한 정확한 이해보다는 기능 구현이 우선이 되었기에, 내가 코드에 적용했던 다른 코드나 기술들에 대해 정확히 왜 사용하고, 어떤 기능인지에 대한 것들은 모두 미뤄뒀었다.

그래서 지금부터 내가 잘 모르고 작성했던 코드들에 대한 공부를 차근히 진행하고자 한다.

나는 아직도 너무 무지하고, 개념을 확실히 알고 넘어 가야 한다는 습관이 완벽히 자리 잡지 않았기에

이 시리즈는 한동안 쭉 작성하지 않을까 싶다.

이 시리즈의 네번째 글의 주제는 DTO에 @Getter@Setter 어노테이션을 왜 사용했을까라는 주제이다.

나는 레퍼런스에서 단순히 DTO마다 @Getter@Setter 어노테이션을 붙여서 사용하길래, 붙이는 이유가 막연히 있겠지라는 생각으로 나 또한 DTO에 @Getter@Setter 어노테이션을 붙였다.

정확히 왜 DTO에 @Getter@Setter 어노테이션을 붙이는 건지에 대해서는 이해하지 못하고 있었다.

이제부터 왜 DTO에 @Getter@Setter 어노테이션을 붙였는지에 대해서 알아보자.

@Getter
@Setter
public class PostRequestDto {

    private String title; // 제목

    private String content; // 내용
    
    private String hashTag; // 해시태그

위 코드는 내가 프로젝트간 작성했던 코드 중 일부 코드이다.

정확히 왜 Getter와 @Getter@Setter 어노테이션을 붙였는지 위 코드를 예시를 들면서 알아보자.



그래서 왜 @Getter, @Setter가 DTO에 있어야 하는데??

흔히 Spring boot로 API 서버를 개발하다보면, JSON → POJO, POJO → JSON등을 @RequestBody@ResponseBody 등을 통해서 데이터 바인딩을 많이 해봤을 것이다.

Spring boot에서는 @RequestBody@ResponseBody 등을 통해서 데이터 바인딩을 할 때 Jackson 라이브러리를 사용한다.

정확히는 Spring의 HttpMessageConverter 인터페이스를 구현한 Jackson2HttpMessageConverter 클래스를 통해 데이터 바인딩을 한다.

위 코드를 여러 경우에 빗대어 Jackson2HttpMessageConverter@Getter@Setter를 어떻게 데이터 바인딩에 이용하는지 알아보자.

1. 필드들이 모두 public인 경우

public class PostRequestDto {

    public String title; // 제목

    public String content; // 내용
    
    public String hashTag; // 해시태그
  • 필드들이 public인 경우 jackson은 멤버변수의 이름을 json 데이터의 key에 매핑 시킨다.
  • ex) title ↔ {”title” : “value”}

2. 필드들이 private이고, @Getter 어노테이션이 있는 경우

@Getter
public class PostRequestDto {

    private String title; // 제목

    private String content; // 내용
    
    private String hashTag; // 해시태그
  • 만약 필드의 접근자가 private, protected이면 Jackson은 @Getter를 통해서 json 데이터의 key와 매핑 시킨다.
  • ex) getTitle ↔ {”title” : “value”}
  • 단 여기서 중요한 점은 Jackson은 getter 메서드의 리턴 값을 Json Value 값으로 사용한다는 것이다. → 물론 이 경우는 직접 getter 메서드를 생성했을 경우이고, LOMBOK을 사용하면 당연히 적용 안되는 예시이다.
    public String getTitle() {
    	return this.title + "입니다.";
    }
    • 위 코드는 이런 JSON으로 바인딩 된다. → {”title” : “value입니다.”}

3. 필드들이 private이고, @Setter 어노테이션이 있는 경우

@Setter
public class PostRequestDto {

    private String title; // 제목

    private String content; // 내용
    
    private String hashTag; // 해시태그
  • 만약 필드의 접근자가 private, protected이면 역직렬화시에 Jackson은 setter를 통해서 Json의 키 값이 @Setter를 통해서 매핑시킨다.
  • 직렬화시에는 에러를 반환하는데, 그 이유는 위에서 알아봤던 것처럼 Jackson은 private 필드인 경우 getter를 통해서 직렬화를 하게 되는데, getter가 없으면 setter를 통해서 필드에 데이터를 담더라도 내보낼 JSON이 만들어지지 않는다.

getter, setter 메서드를 통한 직렬화와 역직렬화를 정리하자면 아래와 같다.

Pojo Json(직렬화)

  • POJO의 getName()의 getter로 인해서 name 필드의 kevin 값이 {”name”:”kevin”}으로 직렬화된다.
  • ResponseDto → Json이 되겠지?

Json POJO(역직렬화)

  • JSON으로 날라온 값이 {”name”:”kevin”} 일 때, 이 데이터를 객체로 바인딩 했을 때 POJO의 getter or setter로 인해서 name 필드와 매핑이 되며, 역직렬화된다.
  • Json → RequestDto이 되겠지?


아니 그러면 DTO에 getter만 있어도 괜찮겠네?

ㅇㅇ 맞다.

정확히는 Jackson이 사용되는 @RequestBody@ResponseBody 를 통한 데이터 바인딩 시에는 getter로 충분하다.

그 외의 경우 Jackson이 사용되지 않는 Get 요청의 경우, 즉 쿼리 파라미터로 값을 넘기는 경우에는 setter를 사용해야 한다. 그 이유는 Get 요청의 경우에는 WebDataBinder를 사용하고, 이는 Java Bean 방식으로 값을 할당하기 때문이다.



내가 Dto에 @Getter, @Setter를 작성했던 이유

답은 Jackson 라이브러리를 통한 데이터 바인딩을 하기 위해서이고, 이 때 @Setter 또한 역직렬화 시 데이터 바인딩을 할 수 있지만, @Getter만으로 충분하다.

profile
Hello, World! \n

0개의 댓글