Jackson ObjectMapper

Content

JOM

Jackson ObjectMapper를 사용해서 DTO를 JSON(문자열)으로 변환하거나, JSON(문자열)을 DTO로 변환할 수 있다. 순서대로 알아보자.

1.먼저, DTO를 위한 class를 만든다.

  • JSON의 스키마를 작성한다는 느낌으로 만들면 된다.

  • Json 문자열의 프로퍼티는 getter 메서드의 이름을 따른다는 점에 주의하자.

    • 예를들어 getTitle이면 프로퍼티(key)의 이름은 title이다.

  • 만약 프로퍼티 이름을 강제하고 싶다면 @JsonProperty 애노테이션을 사용하자.

package com.gyo.api.rest.demo.dtos;

import com.fasterxml.jackson.annotation.JsonProperty;

public class PostDto {

    private String id;

    private String title;

    private String content;

    // Java Beans 규약을 따르는 클래스는 기본 생성자가 필요하다.
    public PostDto() {
    }

    public PostDto(String id, String title, String content) {
        this.id = id;
        this.title = title;
        this.content = content;
    }

    // DTO 특징 : 모든 필드에 대해서 Getter를 제공한다.
    public String getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    // JsonProperty 어노테이션을 사용하면 JSON으로 변환할 때 특정 필드(key)의 이름을 변경할 수 있다.
    @JsonProperty("다른 이름")
    public String getContent() {
        return content;
    }
}

2.Spring DI를 통해 컨트롤러에서 Jackson ObjectMapper를 얻는다. 스프링 프레임워크(DI container)은 등록된 객체(Bean)를 관리하고 있고, 생성자에 명시하면 받아서 사용할 수 있다.

참고로 사용=의존성/의존관계를 주입 받는 것을 말함(Dependency Injection).

Jackson ObjectMapper를 써서 DTO를 JSON 포맷의 String으로 변환한다. JsonProcessingException 예외가 발생할 수 있는데, 여기서는 간단히 JacksonException(상위 예외임) 예외를 사용한다.

3.이렇게 만들고 curl 요청을 해보자

DTO에 getter의 이름에 따라 프로퍼티(key)가 결정되었다. getContent 메서드에 JsonPropery 어노테이션이 붙어있어서 프로 퍼티가 변경된 것을 확인하자.

4.여기서 의문점은 컨트롤러에 objectMapper을 의존성을 주입받았다면 objectMapper가 속한 Jackson 라이브러리를 이미 스프링 부트가 포함하고 있다는 뜻이다. build.gradle을 확인해보자 의존성에 포함된 spring-boot-starter-web에 Jackson이 포함되어있다. 신기하게도 spring boot에서 굳이 컨트롤러에 objectMapper 의존성을 주입 안 해도 DTO를 알아서 변환해주는 기능을 제공한다.

그래서 저렇게 메서드를 작성해도 ResponseBody에 Json String으로 반환된다. 아래와 같이 List형태로 반환해도 알아서 Json String으로 잘 변환해준다.

curl, httpie 요청을 해보았다.

5.objectMapper의 readValue로 String을 DTO로 변환해보자. 아까 objectMapper 의존성을 지웠다면 다시 추가해야한다.

이제 POST 요청을 해보자 메서드 함수 인자에 @RequestBody를 잊지말자. 이게 없으면 요청에서 body에 Json 형태로 보내도 spring boot에서 인식하지 못한다.

@RequestBody 어노테이션은 Spring MVC에서 사용되며, HTTP 요청의 본문(body)을 자바 객체로 매핑(deserialize)할 때 사용됩니다. 이 어노테이션을 사용하지 않으면 Spring은 기본적으로 요청의 본문을 해석하지 않습니다.예를 들어, @RequestBody 없이 메소드 파라미터(함수 인자)에 객체를 사용하면 Spring은 해당 객체를 찾을 수 없어서 해당 파라미터는 null이 됩니다. 따라서 클라이언트에서 보낸 데이터를 읽어들이지 못하게 됩니다.

그리고 DTO에 필드에 대한 setter을 추가하자. 스프링에서 Json String을 읽고 DTO 객체를 만들 때 생성 후 setter을 통해서 필드 값을 주입한다.

지금 PostDTO에 getContent 메서드에 @JsonProperty("다른 이름") 이렇게 어노테이션이 있어서 요청 시 Json의 프로퍼티에 이와 일치하는 "다른 이름"이라는 프로퍼티를 넣어주어야한다.

무심코 content로 프로퍼티 명을 지정하면 null이 나온다.

잠깐 여기서 httpie에서 요청을 보낼 때 Json String으로 기본으로 보내진 것을 알 수 있다. httpie default behavior 위 문서에 따르면 --json 플래그로 명시해주는 방법도 있다고 하니 참고하자. http POST localhost:8080/posts/ id=3 title=gg "다른 이름"=ㅎㅎ --json 이런식으로 말이다.

마찬가지로 curl 요청도 동일하다.

title 이외의 다른 프로퍼티는 요청에 포함하지 않아서 null이 나왔다.

POST API 메서드도 spring-boot-starter-web에 내장된 기능으로 HTTP 요청 시 body를 내부적으로 DTO로 변환해주는 기능을 활용할 수 있다.

메서드 함수 인자의 자료형이 PostDto로 바뀐 것을 확인하자.

CRUD 모두 이런 식으로 DTO를 활용할 수 있다. 이때 적절한 요청 또는 응답을 처리하도록 DTO를 세분화해도 좋다. 예를 들어, Create(POST 요청)에선 id를 직접 넘겨주지 않는다는 걸 명확히 드러내기 위해 id가 없는 DTO를 따로 만들어서 사용해도 된다.

참고 Jackson 활용법 정리

TODO(Jackson 활용법 정리)

https://www.baeldung.com/jackson

Last updated