문제상황


List<Categories> categories = categoriesRepository.findAll();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(categories);

 

문제가 되는 부분은 이렇게 categories 라는 객체 리스트를 mapper 를 이용해서 String 변환시에 발생했다. 

 

 

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 (through reference chain: java.util.ArrayList[0]->com.toco.trialService.entity.Categories["createdDate"])
// ---<이하 생략>

 

 

원인


JUnit5 테스트 중 발생한 문제다. 에러로그 맨 윗줄에서도 볼 수 있듯이 com.fasterxml.jackson.datatype:jackson-datatype-jsr310 모듈java.time.LocalDateTime 타입을 핸들링하지 못한다는 것을 알 수 있다. 즉, categories 라는 객체 리스트를 mapper 를 이용해서 String 변환시에 발생했다. 

 

List<Categories> categories = categoriesRepository.findAll();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(categories);

 

디버깅을 하면 mapper 에서 writeValueAsString 으로 처리할 때,  ObjectMapper.java를 거쳐서 DefaultSerializerProvider 추상클래스 _serialize 메서드를 적용하게 되는데 jackson-datatype 모듈을 인식하지 못한 채로 serialize 하는 과정에서 문제가 발생한다는 것을 알 수 있다.

 

// ObjectMapper.java

protected final void _writeValueAndClose(JsonGenerator g, Object value)
    throws IOException
{
    SerializationConfig cfg = getSerializationConfig();
    if (cfg.isEnabled(SerializationFeature.CLOSE_CLOSEABLE) && (value instanceof Closeable)) {
        _writeCloseable(g, value, cfg);
        return;
    }
    try {
        _serializerProvider(cfg).serializeValue(g, value);
    } catch (Exception e) {
        ClassUtil.closeOnFailAndThrowAsIOE(g, e);
        return;
    }
    g.close();
}
// DefaultSerializerProvider.java

private final void _serialize(JsonGenerator gen, Object value, JsonSerializer<Object> ser)
    throws IOException
{
    try {
        ser.serialize(value, gen, this);
    } catch (Exception e) {
        throw _wrapAsIOE(gen, e);
    }
}

 

 

해결방안


따라서 모듈 인식이 가능하도록 JavaTimeModule()을 인식시켜줄 필요가 있다.

여기서는 registerModule(new JavaTimeModule()) 를 먼저 해주고 String 변환처리를 할 경우, LocalDateTime 인식처리가 가능해진다. 

(다른 블로그 해결방안들에서는 java 버전과 jackson 버전의 문제로 호환을 해주지 않아서 호환되는 버전을 추가해주는 것으로도 해결하는 방안도 보았다.)

 

List<Categories> categories = categoriesRepository.findAll();
ObjectMapper mapper = new ObjectMapper();
String json = mapper.registerModule(new JavaTimeModule()).writeValueAsString(categories);

 

Is there a jackson datatype module for JDK8 java.time? - Stack Overflow

댓글