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
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:
The actual result type is
Class<? extends |X|>
where|X|
is the erasure of the static type of the expression on whichgetClass
is called
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>
.
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.
You need to cast body.getClass()
to 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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With