📌 ParameterizedTypeReference란? - 제네릭 타입을 안전하게 처리하는 방법
스프링의 RestTemplate이나 RestClient를 사용할 때, 응답 데이터를 제네릭 타입으로 안전하게 변환하기 위해 ParameterizedTypeReference<T>를 사용한다.
이는 런타임에서 제네릭 타입을 유지하면서 올바른 타입으로 변환할 수 있도록 도와주는 기능이다.
🚀 1️⃣ Java의 제네릭과 타입 소거 문제
📌 제네릭의 기본 개념
Java에서 제네릭(Generic) 은 클래스나 메서드가 사용할 데이터 타입을 컴파일 시점에서 지정할 수 있도록 해주는 기능이다.
하지만 Java는 타입 소거(Type Erasure) 를 사용하기 때문에, 런타임에는 제네릭 타입 정보가 삭제된다.
List<String> list = new ArrayList<>();
list.add("Hello");
String str = list.get(0); // 정상적으로 작동
위 코드에서는 List<String>을 사용했지만, 런타임에는 List만 남고 제네릭 정보(String)는 사라진다.
🚀 2️⃣ RestClient에서 ParameterizedTypeReference가 필요한 이유
일반적으로 Rest API 호출을 하면, JSON 데이터를 받아서 객체로 변환해야 한다.
하지만 제네릭 타입의 응답을 처리할 때, Java의 타입 소거(Type Erasure) 문제로 인해 정확한 타입을 알기 어렵다.
📌 문제 상황: Rest API 응답을 Map<String, Object>로 변환
Map<string, object=""> response = restClient.post()
.uri("https://api.tosspayments.com/v1/payments/confirm")
.headers(headers -> headers.setBasicAuth(widgetSecretKey, ""))
.body(requestData)
.retrieve()
.body(Map.class); // ❌ 경고 발생
</string,>
위 코드에서 body(Map.class)를 사용하면 컴파일러는 제네릭 정보를 유지하지 못해, 내부 요소의 정확한 타입을 보장할 수 없다.
즉, Map<String, Object>가 아닌 일반적인 Map으로 변환될 수 있다.
✅ 3️⃣ 해결 방법: ParameterizedTypeReference 사용
ParameterizedTypeReference<T>는 런타임에도 제네릭 타입 정보를 유지할 수 있도록 도와주는 클래스이다.
📌 올바른 코드: ParameterizedTypeReference 적용
Map<string, object=""> response = restClient.post()
.uri("https://api.tosspayments.com/v1/payments/confirm")
.headers(headers -> headers.setBasicAuth(widgetSecretKey, ""))
.body(requestData)
.retrieve()
.body(new ParameterizedTypeReference<map<string, object="">>() {});
</map<string,></string,>
✅ 제네릭 타입을 올바르게 유지하면서 JSON 데이터를 변환 가능
✅ 런타임에서도 Map<String, Object>의 정확한 타입 정보를 유지
🚀 4️⃣ ParameterizedTypeReference 사용 예제
📌 예제 1: List<String> 변환
List response = restClient.get()
.uri("https://api.example.com/strings")
.retrieve()
.body(new ParameterizedTypeReference<list>() {});
</list
📌 List.class를 사용하면 List<Object>로 변환될 위험이 있지만, ParameterizedTypeReference<List<String>>()를 사용하면 안전하게 List<String>으로 변환 가능!
📌 예제 2: Map<String, CustomObject> 변환
Map<string, customobject=""> response = restClient.get()
.uri("https://api.example.com/custom")
.retrieve()
.body(new ParameterizedTypeReference<map<string, customobject="">>() {});
</map<string,></string,>
📌 Map.class를 사용하면 내부 타입(CustomObject)을 잃어버릴 수 있지만, ParameterizedTypeReference<Map<String, CustomObject>>()를 사용하면 타입이 안전하게 유지됨.
🎯 결론: 언제 ParameterizedTypeReference를 사용할까?
상황 ParameterizedTypeReference 필요 여부
| List<String> 변환 | ✅ 필요 |
| Map<String, Object> 변환 | ✅ 필요 |
| List<Object> 변환 | ✅ 필요 |
| String, Integer, Boolean 같은 기본 타입 변환 | ❌ 불필요 |
📌 제네릭 타입이 포함된 응답(List<T>, Map<K, V>, Set<T> 등)을 변환할 때는 항상 ParameterizedTypeReference를 사용해야 한다!
📌 정리
- Java의 타입 소거(Type Erasure) 문제로 인해 런타임에서는 제네릭 타입 정보가 사라진다.
- RestClient, RestTemplate에서 제네릭 타입(List<T>, Map<K, V>) 응답을 처리할 때, 정확한 타입 정보를 유지해야 한다.
- 이를 해결하기 위해 ParameterizedTypeReference<T>를 사용하면 제네릭 타입을 안전하게 변환 가능하다.
- 제네릭 타입이 포함된 응답은 항상 ParameterizedTypeReference를 사용하자! 🚀