Jackson으로 LocalDate 자동 매핑하기

recordsbeat·2020년 5월 27일
3
post-thumbnail
post-custom-banner

데이트하는 잭슨

LocalDate를 사용하여 Json으로 통신을 하려다 보면 아래와 같은 일을 마주치기 쉽다.

문제

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of java.time.LocalDate (no Creators, like default construct, exist): no String-argument constructor/factory method to deserialize from String value ('2020-05-25')
at ...

찾아보기

그래서 찾아보면 대부분

@JsonSerialize
@JsonDeserialize
@DateTimeFormat
@JsonFormat

을 사용하라고 한다.

참조링크
이동욱님
SpringBoot에서 날짜 타입 JSON 변환에 대한 오해 풀기
https://jojoldu.tistory.com/361

방법 중의 하나지만 이렇게 될 경우 매번 LocalDate / LocalDateTime의 어노테이션을 매번 설정 해주어야 한다.

Jackson을 조금 알아본 결과 다음과 같이 동작한다고한다.

@Bean에 ObjectMapper등록해 놓고 싱글톤으로 주입 받아서 쓰기 때문에 성능도 우수
[JAVA] JSON 다루기 정리 (JACKSON - ObjectMapper)中
http://bitly.kr/1lp8PJ3InX

내부적으로 ObjectMapper를 사용하여 Object <-> Json 매핑을 진행한다. 그렇다면 ObjectMapper를 원하는 바로 설정하여 @Bean으로 등록하면 되겠다.

해결하기


@Configuration
public class JacksonConfiguration {

    public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Bean
    @Primary
    public ObjectMapper serializingObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer());
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());
        objectMapper.registerModule(javaTimeModule);
        return objectMapper;
    }

    public class LocalDateSerializer extends JsonSerializer<LocalDate> {

        @Override
        public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.format(FORMATTER));
        }
    }

    public class LocalDateDeserializer extends JsonDeserializer<LocalDate> {

        @Override
        public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            return LocalDate.parse(p.getValueAsString(), FORMATTER);
        }
    }
}

어느 외국 사이트에서 찾은 코드를 좀 수정하여 적용한 것이다.
(출처를 찾지 못하여서 죄송 ..ㅠㅠ)

LocalDateSerializer/LocalDateDeserializer 이너클래스에 LocalDate (De)Serialize 방식을 선언해준다.

참조링크
jackson custom serializer, deserializer 만들기
https://multifrontgarden.tistory.com/172

이렇게 열심히 만들어 놓고 테스트 해봤다.

@Test
public void jsonToObj() throws Exception{
	ObjectMapper mapper = new ObjectMapper();
	String json = "{\"id\":202,\"birthDate\":\"2020-05-25\"}";
	ResponseDto result = mapper.readValue(json,ResponseDto.class);
}

안됐다.(위에서 봤던 그 에러)

다음과 같이 사용해야함

@Autowired
ObjectMapper objectMapper;

@Test
public void jsonToObj() throws Exception{
	ObjectMapper mapper = new ObjectMapper();
	String json = "{\"id\":202,\"birthDate\":\"2020-05-25\"}";
	ResponseDto result = mapper.readValue(json,ResponseDto.class);

신나게 Bean객체로 등록해두고 막상 다른 객체를 새로 생성해 쓰니 될리가 없지..테스트코드를 갖고 하루를 날려먹었다.
(테스트에서 저와 같은 삽질 하는 분이 없길ㅠㅠ)

글에서는 위 과정대로 진행된 것처럼 보이지만 코드 먼저 복붙하고 되는지 안되는지 확인해가며 답을 찾았다.(반성)

라이브러리를 사용하기 전에 어떻게 동작하는지 간단하게라도 찾아보는 습관을 기르도록 하자

profile
Beyond the same routine
post-custom-banner

0개의 댓글