[Spring Boot] 커스텀 ObjectMapper 활용하기 + Swagger

boms·2023년 9월 1일
1

Trouble Shooting

목록 보기
4/4

Issue 🙋‍♂️

그동안 API Request, Response body 컨벤션을 snake_case로 해왔다. 그럴때마다 아래와 같이 @JsonNaming 아노테이션을 붙였다.

@JsonNaming(value= PropertyNamingStrategies.SnakeCaseStrategy.class)

클래스가 점점 많아지는데 매번 아노테이션을 달지 않고 하는 방법이 있는지 궁금했다.

Solution 🙌

먼저 Jackson에서 제공하는 ObjectMapper에 주목했다. Jackson은 자바용 Json 라이브러리로 data-processing 툴이다. Jackson의 ObjectMapper는 Json을 Object 데이터로 역직렬화하고 Object를 Json 데이터로 직렬화하는 작업을 해준다. 그런데 ObjectMapper를 커스터마이징하면 Parsing 과정에 조건이나 기능을 추가할 수 있다.

Configuration ⚙️

@Data
@Builder
public class AccountResponse {
    private String name;
    private String email;
    private LocalDateTime registeredAt;
}

위 예시에 대한 ObjectMapper 커스터마이징을 @Configuration 아노테이션으로 했다. 신경써야 할 부분은 snake_case와 (추가) LocalDate 타입 설정이다.

@Configuration
public class ObjectMapperConfig {

    @Bean
    public ObjectMapper objectMapper()

위와 같이 ObjectMapper를 반환하는 메소드를 구현할 것이다. 꼭 @Bean으로 등록해야 default ObjectMapper가 아닌 내가 커스터마이징한 ObjectMapper를 불러 사용할 수 있다. 그리고 아래와 같이 설정했다.

    {
        var objectMapper = new ObjectMapper();
        objectMapper.registerModule(new Jdk8Module());
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

        objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy());

        return objectMapper;
    }
}

objectMapper.registerModule(new Jdk8Module());

필자는 JDK11를 사용하고 있고 JDK8 이상의 클래스를 처리할 수 있도록 설정했다.

objectMapper.registerModule(new JavaTimeModule());

LocalDate 타입인 registeredAt를 위한 설정이다.

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Deserialization(역직렬화)할 때 Object와 매핑되지 않는 Json 데이터가 존재하는 경우 무시하는 설정이다.

objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);

반대로 Serialization(직렬화)할 때 필드가 없는 Object인 경우 무시하는 설정이다.

objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

LocalDate 타입을 직렬화할 때 ISO 8601 형식으로 하는 설정이다.

objectMapper.setPropertyNamingStrategy(new PropertyNamingStrategies.SnakeCaseStrategy());

마지막으로 역직렬화할 때 Json body 컨벤션을 snake_case로 설정한다.

(추가) Swagger❓

Swagger를 사용하여 테스트 해본 결과이다.

registered_at으로 snake_case로 직렬화된 것을 확인할 수 있었다. 하지만 또 다른 문제가 생겼다.

Swagger의 Schemas를 보니 camelCase로 나와있다. 즉 Swagger에도 ObjectMapper를 설정해야 한다.

Solution 🙌

아래와 같이 설정하면 된다.

@Configuration
public class SwaggerConfig {
	@Bean
    public ModelResolver modelResolver(ObjectMapper objectMapper){
        return new ModelResolver(objectMapper);
    }
}

modelResolver 메소드의 호출인데 매개변수 objectMapper는 어디서 어떻게 주입되는지 궁금해서 찾아봤다. 위에서 작성한 ObjectMapperConfig의 objectMapper()에서 Bean 등록한 ObjectMapper가 자동으로 호출되어 주입된다.

잘 바뀌었다.

Takeaway📝

  • ObjectMapper 커스터마이징으로 데이터 Parsing 과정을 설정할 수 있다.
  • 계속 아노테이션을 붙이기 보다는 Configuration으로 일괄 설정 할 수 있게 되었다.
profile
2023.08.21~

0개의 댓글