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