스프링으로 프로젝트를 하다보면 POST요청을 받을 때의 상황에서
@RequestBody Dto dto와 같이 DTO 클래스나 레코드를 만들어서 사용하는 경우가 많을 것이다.
이때 JSON 형식으로 Body를 담아 보낸다고 할 때, 스프링은 이 JSON 문자열을
자동으로 class 인스턴스로 역직렬화 해준다.
이때, json 문자열에 "2025-03-26T14:30:00"와 같은 시간 형식의 문자열을 전송하고,
DTO의 LocalDateTime타입의 멤버가 있을 때도 변환이 문제 없이 동작한다.
(단 SpringBoot는 3.3.5 버전을 사용하였고, 버전이 낮은 경우 동작하지 않을 수 있다)
처음에는 그냥 당연히 되는구나~ 하고 넘어갔는데, ObjectMapper의 동작에 관해서 찾아보면서 코드를 테스트 하던 중, ISO 8601표준에 맞는 시간 형식 문자열이 LocalDateTime으로 변환 되지 않는 오류가 발생하는 것을 확인했다.
하지만, Spring Boot 프로젝트로 할 때와 동일한 Dto형식을 사용했음에도 안되는 것을 보고 좀더 찾아보게 되었다.
테스트를 위해 만든 클래스(레코드)는 아래와 같다
record TestRecord(String name, int age, LocalDateTime date) {
}
그리고 실패한 코드
String json = "{\"name\":\"Hi\",\"age\":30,\"date\":\"2023-10-01T10:00:00\"}";
ObjectMapper objectMapper = new ObjectMapper();
TestRecord testRecord = objectMapper.readValue(json, TestRecord.class);
readValue()에서 런타임 예외가 발생한다.
이에 대해 이유를 찾아보던 중, 이유를 알게 되었다.
ObjectMapper 자체가 원래 String to LocalDateTime을 지원하는 것은 아니고, 이 SpringBoot 프로젝트에서 사용하는 ObjectMapper은 시간 처리를 위한 Module이 따로 등록이 되어있다는 것을 알게 되었다.
@AutoWired를 통해 빈을 가져와서 사용하면 같은 코드지만 변환이 가능한 것을 볼 수 있다.
테스트를 위한 컨트롤러를 하나 만들어서 테스트 해보았다.
@RestController
public class TestController {
@Autowired
private ObjectMapper objectMapper;
@PostMapping("/test")
public String test() throws Exception {
String json = "{\"name\":\"Hi\",\"age\":30,\"date\":\"2023-10-01T10:00:00\"}";
TestRecord testRecord = objectMapper.readValue(json, TestRecord.class); // 정상 동작
return "test";
}
}
달라진 부분은 ObjectMapper을 @AutoWired를 통해 등록된 빈을 가져와서 사용했을 뿐이다.
즉, 등록된 빈의 ObjectMapper은
ObjectMapper objectMapper = new ObjectMapper();
을 통해 새로 만든 ObjectMapper와 다르다는 것이다.
이는 아래 코드를 통해서 확인해볼 수 있다
objectMapper.getRegisteredModuleIds()
매퍼에 등록된 모듈을 보여준다.
ObjectMapper objectMapper = new ObjectMapper();
로 생성한 obejctMapper의 경우 getRegisteredModuleIds()을 하면
size가 0인 set이 EmptyColllection이 반환되고,
스프링 빈에서 가져온 ObjectMapper은 아래 사진과 같이 많은 종류의 등록된 모듈을 확인할 수 있다

참고로 목록 중에서 LocalDateTime변환을 담당하는 모듈은
jakson-datatype-jsr310이다
이렇게 ObjectMapper에 대해 알고있으면 추후에 Custom 클래스도 직렬화/역직렬화를 하기 위한 작업을 수월하게 할 수 있을 것 같다.