Jackson으로 LocalDate 자동 매핑하기

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

데이트하는 잭슨

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

0개의 댓글

관련 채용 정보