Spring boot에서 RabbitMQ로 데이터를 보내는 도중 에러가 발생하였습니다.
해석하자면 java.time.LocalDateTime을 직렬화 하려면 com.fasterxml.jackson.datatype:jackson-datatype-jsr310 디펜던시를 추가해라 ~ 라는 내용입니다.
문제가 발생한 코드입니다. rabbitTemplate는 내부적으로 Object를 매개변수로 받고 ObjectMapper로 직렬화를 하여 메시지를 전송합니다.
이 직렬화 하는 과정에서 LocalDateTime을 직렬화를 지원하지 않으니 exception이 발생합니다.
dependencies {
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
implementation 'com.fasterxml.jackson.core:jackson-databind'
}
필요한 디펜던시를 추가해 주었습니다.
JSON 구조 데이터에 대한 데이터 바인딩을 JAVA 객체에 제공하는 핵심 라이브러리 입니다. JSON data -> Java Object , Java Object -> JSON data 로 직렬화 역직렬화를 가능하게 합니다.
Jackson에서 Java8 날짜/시간 API를 지원하는 확장 라이브러리입니다. LocalDateTime, LocalDate, ZonedDateTIme 등과 같은 Java8 날짜/시간 개체를 JSON data로 직렬화 및 역직렬화할 수 있습니다.
추가 후 LocalDateTime을 사용하는 클래스에 추가로 코드를 작성해줍니다.
public class InitMessage {
// ...코드 생략
@JsonProperty("startDateTime")
@JsonSerialize(using = LocalDateTimeSerializer.class)
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private LocalDateTime startDateTime;
@JsonProperty("endDateTime")
@JsonSerialize(using = LocalDateTimeSerializer.class) // 직렬화 시 필요
@JsonDeserialize(using = LocalDateTimeDeserializer.class) // 역직렬화 시 필요
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSS")
private LocalDateTime endDateTime;
}
이제 ObjectMapper에 직접 모듈을 추가해주도록 하겠습니다. 저는 스프링 부트를 사용하고 있고 생성자 DI를 사용하여 ObjectMapper를 초기화 하도록 하겠습니다.
주석 달린 쪽을 보시면 이해가 되실 겁니다.
@Component
@Slf4j
public class DevReg implements CommandLineRunner {
private final RabbitTemplate rabbitTemplate;
private final ObjectMapper objectMapper;
private final String MSG_EXCHANGE = "exchange.message";
private final String MSG_ROUTING_KEY = "message";
public DevReg(RabbitTemplate rabbitTemplate) {
this.rabbitTemplate = rabbitTemplate;
this.objectMapper = new ObjectMapper();
this.objectMapper.registerModule(new Jdk8Module()); // Jdk8Module 추가
this.objectMapper.registerModule(new JavaTimeModule()); // JavaTimeModule 추가
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
}
@Override
public void run(String... args) throws Exception {
MessageInfo messageInfo = InitMessage
.builder()
// 생략
.startDateTime(LocalDateTime.now())
.endDateTime(LocalDateTime.now())
.build();
rabbitTemplate.convertAndSend(MSG_EXCHANGE, MSG_ROUTING_KEY, messageInfo);
}
}
이렇게 수정 후 다시 메시지를 보내게 되면 exception이 사라지고 데이터가 잘 전송됩니다.