티스토리 뷰
사이드로 진행하고 있는 프로젝트에서 직렬화/역직렬화 시 ObjectMapper를 사용하고 있습니다. 이때 JSON에서 자바 객체로 역직렬화 시 LocalDateTime 필드가 정상적으로 변환되지 않고 오류가 발생하였는데 이를 정리하고자 글을 작성하게 되었습니다.
문제
유저가 북마크 한 게시글 목록의 썸네일 경로를 조회하고자 할 때 위와 같은 응답을 반환합니다. 응답 데이터에는 북마크 ID, 북마크 한 게시글 ID, 게시글의 썸네일 경로, 게시글 작성 일자의 리스트가 담겨있습니다.
MockMvc의 응답 body에 담겨 있는 JSON 정보를 추출하여 객체로 변환 후 예상했던 데이터와 일치하는지 여부를 확인하기 위해 위와 같은 코드를 작성하였습니다. ObjectMapper에 의해 역직렬화가 올바르게 수행될 것이라 예상했지만 아래와 같은 오류가 발생하게 되었습니다.
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling at [Source: ...중략 ]
오류 메시지를 해석하면 다음과 같습니다. Java 8의 날짜/시간 유형은 기본적으로 지원되지 않습니다. 이를 처리하도록 사용하려면 com.fastxml.jackson.datatype:jsr310 모듈을 추가해야 합니다.
해당 오류는 Java 8에 추가된 날짜/시간 타입인 LocalDate, LocalTime, LocalDateTime이 기본적으로 Jackson 라이브러리에 의해 지원되지 않기 때문에 발생하는 것입니다. 이를 해결하려면 com.fastxml.jackson.datatype:jackson-datatype-jsr310
모듈 추가가 필요합니다. 해당 모듈은 Java 8의 날짜/시간 타입은 Jackson에서 처리할 수 있도록 지원해 줍니다.
따라서 해당 모듈을 추가해 주면 문제가 해결될 줄 알았으나, 또 다른 문제가 발생하였습니다.
존재하지 않을 것이라 예상했던 모듈이 이미 프로젝트 모듈에 존재했습니다. 직접적으로 추가해주지 않아도 스프링 부트 다른 모듈에 의해 이미 프로젝트에 존재했던 것입니다. 그렇다면 어떤 모듈이 해당 모듈을 가져왔을까요?
정답은 org.springframework.boot:spring-boot-starter-web
모듈입니다. 해당 모듈에 의해 spring-boot-starter-json
모듈이 따라오고 jackson-datatype-jsr310
모듈도 가져오게 되는 것입니다. 해당 모듈이 있음에도 LocalDateTime의 역직렬화가 되지 않는 이유가 무엇일까요? 그전에 ObjectMapper에 대해 간단히 설명드리도록 하겠습니다.
ObjectMapper
ObjectMapper는 Java에서 JSON을 다루는 데 사용되는 Jackson 라이브러리의 주요 클래스입니다. 주로 JSON과 Java 객체 간의 변환(즉, 직렬화 및 역직렬화)을 담당합니다.
- 직렬화(Serialization) : Java 객체를 JSON으로 변환하는 과정을 직렬화라고 합니다.
- 역직렬화(Deserialization) : JSON을 Java 객체로 변환하는 과정을 역직렬화라고 합니다.
ObjectMapper는 이러한 직렬화 및 역직렬화 작업을 수행하는 다양한 메서드를 제공합니다. 컬렉션 타입, 날짜/시간 타입과 같은 복잡한 데이터 유형을 적절하게 처리하기 위해서는 사용자 정의 모듈을 추가하는 기능도 제공합니다.
결국 복잡한 데이터 유형을 적절하게 처리하기 위해서는 사용자 정의 모듈을 추가해야 함을 알 수 있습니다. 날짜/시간 타입의 데이터를 처리하기 위해 추가해야 하는 모듈은 JavaTimeModule
입니다.
JavaTimeModule
JavaTimeModule은 Java 8에 도입된 새로운 날짜 및 시간 API(LocalDate, LocalTime, LocalDateTime)를 Jackson 라이브러리에서 적절하게 처리할 수 있게 해주는 모듈입니다. 기본적으로 Jackson 라이브러리는 Java 8의 새로운 날짜 및 시간 타입들을 인식하지 못하기 때문에 해당 타입들을 JSON으로 직렬화하거나 JSON에서 역직렬화할 때 문제가 발생할 수 있습니다.
이러한 문제를 해결하기 위해 JavaTimeModule을 ObjectMapper에 등록하면 날짜/시간 타입들을 적절하게 직렬화하고 역직렬화할 수 있게 됩니다.
왜 미리 등록되어 있지 않을까
기본 설정으로 Java 8의 날짜/시간 타입을 정확히 처리하지 못하는 이유는 해당 타입들은 표준 Java 라이브러리 일부가 아니라 Java 8에 처음 도입된 JSR 310 날짜/시간 API의 일부이기 때문입니다. 따라서 ObjectMapper에 해당 모듈 등록이 필요하고, 등록한다면 Java 8 날짜/시간 타입을 적절하게 직렬화, 역직렬화할 수 있는 것입니다.
해결
@Configuration
public class ModuleConfig {
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
return objectMapper;
}
}
위의 코드와 같이 JavaTimeModule을 등록한 ObjectMapper를 스프링 빈으로 등록하여 사용하면 됩니다. 등록한 ObjectMapper를 사용하면 날짜/시간 타입에 대해서도 직렬화 및 역직렬화가 정상적으로 동작하는 것을 확인할 수 있습니다.
'Spring' 카테고리의 다른 글
[Spring] BeanFactory, ApplicationContext (0) | 2023.05.14 |
---|---|
[Spring] 스프링을 어노테이션 기반으로 만든 이유 (1) | 2023.05.02 |
[Spring] @Controller가 뷰 이름을 반환하지 않는다면 (2) | 2023.04.25 |
[Spring] RestTemplate 알아보기 (2) | 2023.04.22 |