balteo balteo - 10 days ago 6
Java Question

Issue with type parameter: "cannot select from parameterized type"

I am facing an issue with generics.

Here is one of my classes that uses generics:

public class TokenServerResponse<D> {

private String responseCode;
private String responseMessage;
private D responseData;
....


Here our class:
TokenServerResponse
is parameterized with
D
.

I would like to specify the type in one of our methods as follows:

protected ResponseEntity<TokenServerResponse<DigestResponseData>> digest(long globalMerchantUId, String expirydate, String pan, boolean updateExpiryDate) throws Exception {
DigestRequest digestRequest = new DigestRequest();
digestRequest.setGlobalMerchantUid(globalMerchantUId);
digestRequest.setExpiryDate(expirydate);
digestRequest.setPan(pan);
digestRequest.setUpdateExpiryDate(updateExpiryDate);
return restTemplate.postForEntity("/digest", digestRequest, TokenServerResponse<DigestResponseData>.class);
}


However, I get the following compiler error:
cannot select from parameterized type
.

How can I use the type parameter
D
? I have also tried casting to no avail. What am I getting wrong?

Here is how the
digest
method is called:

ResponseEntity<TokenServerResponse<DigestResponseData>> digestResponseEntity = digest(823, "1505", pan, true);

Answer

Here :

return restTemplate.postForEntity("/digest", digestRequest, TokenServerResponse<DigestResponseData>.class);

If your method expects to have a class value as last argument, you can only provide a class for it. Providing a class with generic type is not possible.
Casting is unavoidable but if you change your TokenServerResponse class to use also inheritance.

public abstract class TokenServerResponse<T> {
    private String responseCode;
    private String responseMessage;
    private T responseData;

    public T getResponseData() {
        return responseData;
    }
}

public class TokenServerResponseDigestResponseData extends TokenServerResponse<DigestResponseData> {

}

Now you can use TokenServerResponseDigestResponseData class here :

return restTemplate.postForEntity("/digest", digestRequest, TokenServerResponseDigestResponseData.class);

And when you do :

TokenServerResponseDigestResponseData instance = ...
DigestResponseData data = instance.getResponseData();

you don't need any cast.

Of course this solution is interesting if you have not dozen of classes to make them inherited from the TokenServerResponse class and you would like to work with specific types in client code.
In your case, DigestResponseData is required to make your processing since your generic type doesn't rely on a specific type but on Object type, so you should cast at a time in this way : TokenServerResponse to TokenServerResponse<DigestResponseData>. With the proposed solution, it is not required any longer.