I have a candy factory that exposed various endpoints to get candies in a bag.
candy such as
Api response pattern is below
public class CandyWrapper <T> {
@JsonProperty("candies")
private List<T> candies;
}
I have a generic service class which deals with getting the candies using Spring RestTemplate
public class CandyStore<T> {
private final RestTemplate restTemplate;
private final Class<CandyWrapper<T>> type
String candyFactroyUrl;
public CandyStore(Class<CandyWrapper<T>> type, RestTemplate restTemplate, String
factoryUrl) {
this.type = type;
....
....
}
public CandyWrapper<T> getCandies(){
HttpEntity<HttpHeaders> request = new HttpEntity<>();
ResponseEntity<CandyWrapper<T>> response;
response = restTemplate.exchange(candyFactroyUrl, HttpMethod.GET, request, type);
return response.getBody();
}
}
Now when I am going to configure the CandyStore service with the actual type of the Candy ; Unable to determine the candy type to pass in the service constructor.
@Bean()
public getSkittleCandyStore(RestTemplate restTemplate, String skittleUrl){
//TODO
get the class of type CandyWrapper<Skittle> so that I can pass it to the service
constructor.
CandyWrapper<Skittle> instance = new CandyWrapper<Skittle>();
// instance.getClass() does not give the class conforming to the parameter below.
return new CandyStore(???, restTemplate, skittleUrl);
}
Any help to clear up the generics concepts is appreciated. Thanks!!
Java generics undergo type erasure, meaning they don't retain their generic type at runtime, so CandyWrapper<Skittle>.class
just wont' work.
You may try to use ParameterizedTypeReference
from Spring instead, which provides an abstract class that you simply subclass to capture the generic type, like:
@Bean
public CandyStore<Skittle> getSkittleCandyStore(
RestTemplate restTemplate,
String skittleUrl
) {
return new CandyStore<>(
new ParameterizedTypeReference<CandyWrapper<Skittle>>() {},
restTemplate,
skittleUrl
);
}
and CandyStore
:
public class CandyStore<T> {
private final RestTemplate restTemplate;
private final ParameterizedTypeReference<CandyWrapper<T>> typeRef;
String candyFactroyUrl;
public CandyStore(ParameterizedTypeReference<CandyWrapper<T>> typeRef, RestTemplate restTemplate, String factoryUrl) {
this.typeRef = typeRef;
this.restTemplate = restTemplate;
this.candyFactroyUrl = factoryUrl;
}
public CandyWrapper<T> getCandies(){
HttpEntity<HttpHeaders> request = new HttpEntity<>();
ResponseEntity<CandyWrapper<T>> response;
response = restTemplate.exchange(candyFactroyUrl, HttpMethod.GET, request, typeRef);
return response.getBody();
}
}
so please, make sure to update the restTemplate.exchange
to use the new typeRef
field instead, should looks like:
response = restTemplate.exchange(candyFactroyUrl, HttpMethod.GET, request, typeRef);
Read more about ParameterizedTypeReference
: