1. 문제 상황
Kafka topic에 이벤트를 발행하기 위해서는 java 객체를 JSON 으로 직렬화하는 과정이 필요하다.
이 때 변환하려는 이벤트에 LocalDateTime 타입의 필드가 있었고, 직렬화하는 과정에서 문제가 발생했다.
ReservationCreatedEvent
public record ReservationCreatedEvent(
UUID reservationId,
Long userId,
UUID restaurantScheduleId,
LocalDateTime createdAt, // LocalDateTime
LocalDateTime expiredAt // LocalDateTime
)
createdAt, expiredAt 이라는 필드가 LocalDateTime 이고,
이것을 JSON 으로 직렬화하는 과정에서 문제가 발생한 것이다.
"Java 8 날짜/시간 타입은 기본값으로 지원되지 않는다" 는 내용의 예외가 발생한 것을 확인할 수 있다.
2. 원인 분석
Spring Boot 애플리케이션에서는 기본적으로 제공되는 라이브러리인 Jackson 라이브러리는
LocalDateTime 을 비롯한 java.time 패키지 내에 클래스들을 변환하지 못한다.
java 8 날짜/시간 API(JSR-310)가 Jackson의 기본 지원 대상에 포함되지 않기 때문이다.
이로 인해 JSON 직렬화 및 역직렬화 과정에서 오류가 발생한 것이다.
Jackson은 초기 설계 시 Java 8 이전의 날짜/시간 클래스(java.util.Date, java.util.Calendar)를
지원하도록 만들어졌다.
Java 8에서 새롭게 도입된, LocalDateTime, LocalDate, LocalTime 등은
Jackson의 기본 모듈에서 처리되지 않는다.
또한, Java 8의 날짜/시간 클래스는 불변 객체로 설계되었으며, Jackson 직렬화 로직과 호환되지 않는다.
Jackson은 날짜/시간 객체를 POJO로 직렬화하려고 시도하며,
이를 처리할 생성자나 팩토리 메서드가 없으면 오류를 발생 시킨다.
3. 해결 방법
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
해결 방법으로는 Jackson에 추가 모듈을 등록해야 한다.
Jackson은 Java 8 날짜/시간 API를 지원하기 위해 별도의 모듈인 jackson-datatype-jsr310을 제공한다.
해당 의존성을 추가한 후, ObjectMapper에 JavaTimeModule을 등록하면
Jackson이 Java 8 날짜/시간 타입을 처리할 수 있다.
@Slf4j
public class EventSerializer {
private static final ObjectMapper objectMapper = new ObjectMapper()
.registerModule(new JavaTimeModule()); // JavaTimeModule 등록
// 직렬화 (객체 -> JSON 문자열)
public static <T> String serialize(T object) {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
log.error("Failed to serialize object: {}", object, e);
throw new RuntimeException("Serialization error", e);
}
}
// 역직렬화 (JSON 문자열 -> 객체)
public static <T> T deserialize(String json, Class<T> clazz) {
try {
return objectMapper.readValue(json, clazz);
} catch (JsonProcessingException e) {
log.error("Failed to deserialize JSON: {}", json, e);
throw new RuntimeException("Deserialization error", e);
}
}
}
References
https://jcp.org/aboutJava/communityprocess/pfd/jsr310/JSR-310-guide.html
https://docs.oracle.com/javase/8/docs/api/java/time/package-summary.html
'Spring' 카테고리의 다른 글
Spring AOP를 활용해서 권한 체크 하기 (0) | 2025.03.06 |
---|---|
운영 환경에서 Spring Cloud Config Server를 의존하지 않으려면 (0) | 2025.01.21 |
Spring Boot 에서 Snake Case 형식으로 JSON 응답하기 (0) | 2025.01.08 |