데이트하는 잭슨
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객체로 등록해두고 막상 다른 객체를 새로 생성해 쓰니 될리가 없지..테스트코드를 갖고 하루를 날려먹었다.
(테스트에서 저와 같은 삽질 하는 분이 없길ㅠㅠ)
글에서는 위 과정대로 진행된 것처럼 보이지만 코드 먼저 복붙하고 되는지 안되는지 확인해가며 답을 찾았다.(반성)
라이브러리를 사용하기 전에 어떻게 동작하는지 간단하게라도 찾아보는 습관을 기르도록 하자