Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

generics

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);
like image 378
balteo Avatar asked Nov 29 '16 10:11

balteo


People also ask

Which methods Cannot be type parameterized?

6. Which of these Exception handlers cannot be type parameterized? Explanation: we cannot Create, Catch, or Throw Objects of Parameterized Types as generic class cannot extend the Throwable class directly or indirectly.

Can a parameterized type have several bounds?

A type parameter can have multiple bounds.

What is type parameters in generics?

In a generic type or method definition, a type parameter is a placeholder for a specific type that a client specifies when they create an instance of the generic type.

Is a raw type should be parameterized?

In summary, raw types should NEVER be used in new code. You should always use parameterized types.


1 Answers

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.

like image 162
davidxxx Avatar answered Sep 29 '22 14:09

davidxxx