I am trying to understanding how the generics work in case of Mockito.
I am trying to mock the RestTemplate, however the following code does not compile and I don't know why:
var expectedResponse = createServiceResponse();
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
Mockito.<HttpEntity<Object>>any(),
Mockito.<ServiceResponse>any().getClass(), anyMap()))
.thenReturn(ResponseEntity.ok(expectedResponse));
The compiler keeps giving me the error message:
Cannot resolve method 'thenReturn(org.springframework.http.ResponseEntity<T>)
But when I switch Mockito.<ServiceResponse>any().getClass() with Mockito.<Class<ServiceResponse>>any() the compilation succeeds.
Why is this happening ?
What is the difference between Mockito.<ServiceResponse>any().getClass() and Mockito.<Class<ServiceResponse>>any() ?
They should be the same thing right ?
I mean the class of ServiceResponse should be Class<ServiceResponse>. Right ?
I don't have a good grasp of advanced generics so I can't understand what the compiler is doing.
Please do add some description in the answer so that I can understand why this is working the way it is suppose to.
CodePudding user response:
Only in these cases, where the compiler cannot garantuee the returned type of the method (here restTemplate.exchange) we can use the non-type-safe equivalent syntax:
Mockito.doReturn(ResponseEntity.ok(expectedResponse))
.when(restTemplate)
.exchange(anyString(), any(HttpMethod.class),
Mockito.<HttpEntity<Object>>any(),
Mockito.<ServiceResponse>any().getClass(), anyMap()));
CodePudding user response:
What is the difference between Mockito.<ServiceResponse>any().getClass() and Mockito.<Class<ServiceResponse>>any()?
Mockito.<ServiceResponse>any() is an instance of ServiceResponse. And calling getClass() from any instance return Class<?>. getClass() is created to get the actual class of the instance, usually for runtime comparison.
On the other hand,
Mockito.<Class<ServiceResponse>>any() is an instance of Class<ServiceResponse>
I mean the class of ServiceResponse should be Class. Right ?
Not really, consider following code
private void dummy(ServiceResponse response) {
System.out.println(response.getClass().equals(ServiceResponse.class));
}
You can't guarantee the output is always true, as response can be of type CustomServiceResponse(extending ServiceResponse)
For your problem, just use ServiceResponse.class, simple and clear.
Further reading:
What is the difference between a.getClass() and A.class in Java?
Why does a wildcard on a generic parameter require an explicit cast?
Java: getClass() of bounded type
