Generic method, equality constraint

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


Generic method, equality constraint



Hello Im trying to implement a generic method as controller base method, but the problem which I cannot understand happens with the generic method signature.


<T> ResponseEntity<T> makeApiCall(String path, HttpMethod httpMethod, T body, boolean isAdmin){

String sender = isAdmin ? adminHash : userHash;
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", sender);
headers.add("Content-Type", "application/json");
HttpEntity<T> entity = new HttpEntity<>(body,headers);
ResponseEntity<T> responseEntity = restTemplate.exchange(path, HttpMethod.POST, entity, body.getClass());
return responseEntity;
}



The compile error I currently have is as follows:


Incompatible equality constraint: T and capture of ? extends Object




2 Answers
2



You don't say exactly where the problem occurs, but I think this will occur on the restTemplate.exchange( call, as a result of passing body.getClass() as a parameter. This is because the return type of body.getClass() is Class<? extends Object>, as in the Javadoc:


restTemplate.exchange(


body.getClass()


body.getClass()


Class<? extends Object>



The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called


Class<? extends |X|>


|X|


getClass



The problem is that you can't guarantee that body is specifically a T - it could be a subclass of T. As such, the result of body.getClass() might not be a Class<T>.


body


T


T


body.getClass()


Class<T>



If you want to be type-safe, you would need to pass that in as an additional parameter to the method.


<T> ResponseEntity<T> makeApiCall(
String path, HttpMethod httpMethod, T body, Class<T> bodyClass,
boolean isAdmin){
// ...
ResponseEntity<T> responseEntity =
restTemplate.exchange(
path, HttpMethod.POST, entity, bodyClass);
// ...
}



Note that the only way to obtain a Class<T> is to use a class literal, e.g. String.class if T is String. This precludes the use of generic body types, since there are no generic class literals.


Class<T>


String.class


T


String





"the only way to obtain a Class<T> is to use a class literal, e.g. String.class if T is String. This precludes the use of generic body types, since there are no generic class literals" seems to contradict itself. Anyway, at compile time the compiler can figure out the generic type. And what about assigning a getClass() result to a Class<T> variable?
– Lew Bloch
Feb 18 '17 at 18:20


getClass()


Class<T>





@LewBloch: I think what he means is that T must be a reifiable type. Otherwise say if T is a parameterized type like Foo<Bar>, then you would somehow have to provide a Class<Foo<Bar>>, which doesn't really exist safely.
– newacct
Feb 24 '17 at 8:11




T


T


Foo<Bar>


Class<Foo<Bar>>



You need to cast body.getClass() to Class<T>


cast body.getClass()


Class<T>


@SuppressWarnings("unchecked")
<T> ResponseEntity<T> makeApiCall(String path, HttpMethod httpMethod, T body, boolean isAdmin){

String sender = isAdmin ? adminHash : userHash;

HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", sender);
headers.add("Content-Type", "application/json");
HttpEntity<T> entity = new HttpEntity<>(body,headers);
ResponseEntity<T> responseEntity = restTemplate.exchange(path, HttpMethod.POST, entity, (Class<T>) body.getClass());
return responseEntity;
}



To make it type-safe you need to pass the class object as a parameter explicitly:


<T> ResponseEntity<T> makeApiCall(String path, HttpMethod httpMethod, T body, Class<T> clazz, boolean isAdmin){
String sender = isAdmin ? adminHash : userHash;

HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", sender);
headers.add("Content-Type", "application/json");
HttpEntity<T> entity = new HttpEntity<>(body,headers);
ResponseEntity<T> responseEntity = restTemplate.exchange(path, HttpMethod.POST, entity, clazz);
return responseEntity;
}





Generic casts raise warnings that you should handle.
– Lew Bloch
Feb 18 '17 at 18:21






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Arduino Mega cannot recieve any sketches, stk500_recv() programmer is not responding

Visual Studio Code: How to configure includePath for better IntelliSense results

C++ virtual function: Base class function is called instead of derived