Java로 프로젝트를 진행하다 보면 ObjectMapper를 많이 사용해 봤을 것이다.
ObjectMapper는 JSON 데이터와 객체 간의 직렬화/역직렬화와 데이터 타입 간의 변환을 도와주는 고마운 놈이다.
그런데 오늘 제네릭 타입 필드를 갖는 객체로 변환을 하던 중에 문제가 생겼다.
자바의 제네릭은 컴파일 시점에 타입 파라미터를 확인한 후 런타임에는 타입을 제거하는 방법을 사용한다. (Generic Type Erasure)
public class CustomPagingDto<T> {
private int pageIndex;
private int pageSize;
private long totalCount;
private int totalPage;
private List<T> data;
}
코드를 보면 data라는 필드는 다양한 타입이 올 수 있도록 List<T>로 제네릭 타입으로 되어있다.
CustomPagingDto pagingDto = objectMapper.convertValue(response, CustomPagingDto.class);
API를 호출하고 받은 응답을 CustomPagingDto로 변환하기위해 ObjectMapper의 convertValue()를 사용했다.
하지만, 런타임 시점이라 data 필드의 제네릭 타입이 무엇인지 모르기 때문에 에러가 발생했다.
ObjectMapper의 readValue(), convertValue()들은 어떤 타입으로 변환할지 Class, TypeReference, JavaType 중 1개를 파라미터로 받는데 위의 코드처럼 CustomPagingDto<Member>.class 처럼 클래스가 파라미터를 포함한 경우 포함된 파라미터를 Parameterized Type이라 해서 포함된 파라미터를 ObjectMapper에게 전달해줘야한다.
TypeReference를 사용하거나 TypeFactory의 constructParametricType()을 사용하여 2가지 방법으로 전달할 수 있다.
1. TypeReference 사용
CustomPagingDto<Member> pagingDto = objectMapper.convertValue(response, new TypeReference<CustomPageDto<Member>>() {});
TypeReference를 사용하면 ObjectMapper에게 CustomPagingDto의 data가 Member타입이라는 것을 전달할 수 있다.
2. TypeFactory 사용
JavaType javaType = objectMapper.getTypeFactory().constructParametricType(CustomPageDto.class, Member.class);
CustomPagingDto<Member> pagingDto = objectMapper.convertValue(response, javaType);
TypeFactory의 constructParametricType()을 사용해 JavaType을 만들어 ObjectMapper에게 전달한다.
앞으로도 형변환 시 ObjectMapper를 많이 사용할 텐데 ObjectMapper 유틸클래스에 적용하여 편리하게 사용해야겠다.
화이팅!
'Java' 카테고리의 다른 글
[Java] try-with-resources (0) | 2024.04.22 |
---|---|
[Java] instanceof pattern matching (0) | 2024.04.22 |
[Java] 비어있는 리스트(Collections.emptyList()) (2) | 2023.10.31 |