balteo
balteo

Reputation: 24679

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);

Upvotes: 15

Views: 16900

Answers (1)

davidxxx
davidxxx

Reputation: 131456

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.

Upvotes: 16

Related Questions