This is related to this issue, and I know we have a test to confirm that is not an issue. However the issue I found is that it only works when we explicitly specify the type like this bodyToMono(new ParameterizedTypeReference<ValueContainer<Foo>>() {})
. It will not work if we move that webClient.get()
block to a separate function and change it to take generic type like this bodyToMono(new ParameterizedTypeReference<ValueContainer<T>>() {});
.
Here is the modified unit test. It will throw error class java.util.LinkedHashMap cannot be cast to class org.springframework.web.reactive.function.client. WebClientIntegrationTests$Foo
@Test
public void shouldReceiveJsonAsTypeReferenceString() throws Exception {
String content = "{\"containerValue\":{\"fooValue\":\"bar\"}}";
prepareResponse(response -> response
.setHeader("Content-Type", "application/json").setBody(content));
Mono<ValueContainer<Foo>> result = getData();
StepVerifier.create(result)
.assertNext(valueContainer -> {
Foo foo = valueContainer.getContainerValue();
assertNotNull(foo);
assertEquals("bar", foo.getFooValue());
})
.expectComplete().verify(Duration.ofSeconds(3));
expectRequestCount(1);
expectRequest(request -> {
assertEquals("/json", request.getPath());
assertEquals("application/json", request.getHeader(HttpHeaders.ACCEPT));
});
}
private <T> Mono<ValueContainer<T>> getData() {
return this.webClient.get()
.uri("/json").accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<ValueContainer<T>>() {});
}
Spring boot version is 2.5.3
Comment From: poutsma
You are running into one of the limitations of the Java type system. In order for ParameterizedTypeReference
to work, it needs to be bound to a specific type at compile time, and cannot be used in the generic way shown in the test. For more information about this topic, see this article.
In other words: there is nothing that Spring can do to fix this.
Comment From: anhtuta
I think this will work
private <T> Mono<ValueContainer<T>> getData(Class<T> responseType) {
return this.webClient.get()
.uri("/json").accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(responseType);
}