RestController에서 ResponseDto로 멤버변수 없이 반환하기 | MappingJackson2HttpMessageConverter

beomdrive·2022년 11월 10일
0

삽질 저장소

목록 보기
3/4

상황

RestController에서 Entity를 ResponseDto로 변환하여 응답값을 반환하는 상황이다.
Dto has a Entity 구조로 만들어보았다.

각 getter 메소드를 다시 코딩하는 것으로 변화하는 상황에 대응할 수 있다?
잘 이해가 되지 않아 코드를 작성해보았다.

[코드]

public class CreateProductResponseDto {
    @JsonIgnore
    private Product product;

    public CreateProductResponseDto(Product product) {
        this.product = product;
    }

    public Long getId() {
        return this.product.getId();
    }

    public String getName() {
        return this.product.getName();
    }

    public String getMaker() {
        return this.product.getMaker();
    }

    public Integer getPrice() {
        return this.product.getPrice();
    }

    public String getImageUrl() {
        return this.product.getImageUrl();
    }
}

[결과]

CreateProductResponseDto에는 id, name, maker등의 변수를 선언하지 않고 오로지 Entity 하나만 선언하고 각 getter만 재정의를 해줬다.
그런데 어떻게 별다른 변수가 없이 값이 잘 반환될까?


분석

내 상식에서는 이해가 되지 않아 궁금증을 참지 못하고 무작정 IntelliJ의 Force step into 기능을 사용하여 코드를 까보았더니 딱 눈에 들어온 친구가 있었다. // inlined 'get()'?
뭔가 게터를 호출한다고 외치고 있는 주석인 것 같았다.

이 다음으로 디버깅을 넘겨보니 아래와 같이 CreateProductResponseDto에 한 getter로 이동했다!


검색

위에서 CreateProductResponseDto의 한 getter를 호출하는 객체는 jackson-databind 라이브러리 패키지에 있는 것을 확인했다.

구글링을 통해 해당 블로그에서 Jackson에 관한 해답을 찾았다.

  • Jackson은 기본적으로 Java의 프로퍼티(Getter, Setter)로 동작한다.
  • 따라서 Jackson을 사용하려면 Getter에 신경써야햔다.
  • Getter가 아닌 멤버변수자체로 데이터 매핑을 하고싶다면, @JsonProperty를 사용하여 지정해주면 된다.

그렇다면 Controller 반환 시에 왜 Jackson을 사용할까?
기존에 알고있던 내용으로는 RestController는 값을 반환할 때, 기존 Controller와는 다르게 ViewResolver 대신 MessageConverter를 통해 알맞은 응답 형태로 리턴한다.
이 때 Content-Typeapplication/json이라면 Jackson을 사용하는 것으로 알고 있었다.

추가적인 정보 및 확인은 토비의 스프링 2권 615~616쪽해당 블로그에서 찾아보았다.

  • application/json 콘텐츠 타입으로 전달되는 요청은 MappingJackson2HttpMessageConverter을 통해 메서드 반환 타입 오브젝트로 변환된다.
  • Json의 각 요소와 일치하는 프로퍼티에 자동으로 바인딩된다. (이 때 getter를 사용한다)

[결론]

Controller가 반환할 때 Jackson에 의해 CreateProductResponseDto의 모든 프로퍼티(getter)가 호출되므로 별다른 변수를 선언하지 않아도 정상적으로 반환하는 것이었다!


테스트

이유를 알았으니 한번 더 따로 테스트를 해보자.
테스트 코드를 짤까 하다가, 직관적으로 반환된 데이터를 보고 싶어서 실제 Spring으로 진행하였다.
아래에서 프로퍼티(getter)는 3개의 정상 getter와 1개의 비정상 코드를 집어넣어봤다!

[코드]

public class CreateProductResponseTest {

    public CreateProductResponseTest(Product product) {
    }

    public Long getIdTestHolyMoly() { // 정상
        return 500L;
    }

    public String getNameTestMolyHoly() { // 정상
        return "기범 최고";
    }

    public String getMakerWowAmazing() { // 정상
        return "안양 최고";
    }

    public Integer ohMyGod() { // 비정상 (get으로 시작하지 않음)
        return 5000000;
    }
}

[결과]

앞에 get으로 시작하는 프로퍼티들은 정상적으로 반환되고, ohMyGod()은 데이터 매핑에서 제외된 것을 볼 수 있다.


Reference

profile
꾸준함의 가치를 향해 📈

0개의 댓글