Using Spring RestTemplate in generic method with generic parameter

No, it is not a bug. It is a result of how the ParameterizedTypeReference hack works.

If you look at its implementation, it uses Class#getGenericSuperclass() which states

Returns the Type representing the direct superclass of the entity (class, interface, primitive type or void) represented by this Class.

If the superclass is a parameterized type, the Type object returned must accurately reflect the actual type parameters used in the source code.

So, if you use

new ParameterizedTypeReference<ResponseWrapper<MyClass>>() {}

it will accurately return a Type for ResponseWrapper<MyClass>.

If you use

new ParameterizedTypeReference<ResponseWrapper<T>>() {}

it will accurately return a Type for ResponseWrapper<T> because that is how it appears in the source code.

When Spring sees T, which is actually a TypeVariable object, it doesn't know the type to use, so it uses its default.

You cannot use ParameterizedTypeReference the way you are proposing, making it generic in the sense of accepting any type. Consider writing a Map with key Class mapped to a predefined ParameterizedTypeReference for that class.

You can subclass ParameterizedTypeReference and override its getType method to return an appropriately created ParameterizedType, as suggested by IonSpin.


I am using org.springframework.core.ResolvableType for a ListResultEntity :

    ResolvableType resolvableType = ResolvableType.forClassWithGenerics(ListResultEntity.class, itemClass);
    ParameterizedTypeReference<ListResultEntity<T>> typeRef = ParameterizedTypeReference.forType(resolvableType.getType());

So in your case:

public <T> ResponseWrapper<T> makeRequest(URI uri, Class<T> clazz) {
   ResponseEntity<ResponseWrapper<T>> response = template.exchange(
        uri,
        HttpMethod.POST,
        null,
        ParameterizedTypeReference.forType(ResolvableType.forClassWithGenerics(ResponseWrapper.class, clazz)));
    return response;
}

This only makes use of spring and of course requires some knowledge about the returned types (but should even work for things like Wrapper>> as long as you provide the classes as varargs )