gwimong's blog Software Engineer

Spring에서 Localdatetime이 Array 형태로 표출 되는 현상

jackson-datatype-jsr310와 MvcEnable

오류 현상

Spring에서 LocalDateTime을 JSON으로 변환 시 Array 형태로 표출 되는 현상이 발생하였습니다.

{
    "id": 1,
    "name": "test",
    "createdAt": [
        2023,
        7,
        27,
        15,
        47,
        7,
        972737100
    ],
    "updatedAt": [
        2023,
        7,
        27,
        15,
        47,
        7,
        972737100
    ]
}

원인 분석

Spring 2.0.0이상의 버전에서는 데이터 반환 시 별다른 설정을 하지 않아도 LocatDateTime의 값을 String 으로 자동으로 변환하여 반환합니다.
이는 jackson-datatype-jsr310가 기본적으로 포함되어 있어 있기 때문입니다.

Add-on module to support JSR-310 (Java 8 Date & Time API) data types.

하지만, EnableWebMvc를 설정하면 Springd은 자체적으로 기본적인 ObjectMapper를 구성하게 됩니다.
이로 인해 직렬화와 관련된 설정들이 변경될 수 있으며, 사용자 정의 설정이 무시될 수 있습니다.

(Spring 2.7.0 기준)
Spring이 WebMvcConfigurerAdapter 클래스를 자동으로 등록할 때, configureMessageConverters 메서드를 재정의하고. 이 때 jackon-datatype-jar310이 적용되지 않는 것으로 추측됩니다.

해결 방안

이러한 문제를 해결하기 위해서는 해당 필드에 JsonFormat를 지정하거나, ObjectMapper를 등록 또는 재정의하는 방법이 있습니다.

  1. Spring MVC 비활성화
    • @EnableWebMvc 제거
    • WebMvcConfigurationSupport -> WebMvcConfiguration

  2. JsonFormat
    가장 간단한 방법으로, 해당 필드에 @JsonFormat를 지정하는 방법입니다.
     @JsonFormat(shape = JsonFormat.Shape.STRING,
     pattern = "yyyy/MM/dd'T'HH:mm:ss")
     private LocalDateTime createdAt;
    

    간단하게 적용 할 수 있는 장점이 있지만, 매번 필드에 정의 해줘야 하는 불편함이 있습니다.

  3. 사용자 정의 ObjectMapper 등록
    사용자가 ObjectMapper를 구현하고 이를 Spring에 등록하는 방법입니다.
     @Configuration
     public class WebMvcConfig implements WebMvcConfigurer {
         @Override
         public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
             MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
             converter.setObjectMapper(customObjectMapper());
             converters.add(converter);
         }
    
         @Bean
         public ObjectMapper customObjectMapper() {
             ObjectMapper objectMapper = new ObjectMapper();
             // 여기에 원하는 ObjectMapper 설정을 추가할 수 있습니다.
            return objectMapper;
         }
     }
    


  4. ObjectMapper 재정의
    Jackson2ObjectMapperBuilder 클래스를 재정의하는 방법입니다.
     @Configuration
     public class WebMvcConfig implements WebMvcConfigurer {
         @Override
         public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
             converters.add(mappingJackson2HttpMessageConverter());
         }
    
         @Bean
         public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
             Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
             builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
             builder.dateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
             return new MappingJackson2HttpMessageConverter(builder.build());
         }
     }
    

Similar Posts

Comments