Use IntrospectingClientHttpResponse in RestClient

This commit ensures that the RestClient uses the
IntrospectingClientHttpResponse to verify whether the response has a
body, and return null if it does not.

See gh-12671
Closes gh-31719
This commit is contained in:
Arjen Poutsma 2023-12-01 14:22:58 +01:00
parent 0dbb0f5c14
commit d204dd2dbe
2 changed files with 33 additions and 5 deletions

View File

@ -184,32 +184,40 @@ final class DefaultRestClient implements RestClient {
return new DefaultRestClientBuilder(this.builder);
}
@Nullable
@SuppressWarnings({"rawtypes", "unchecked"})
private <T> T readWithMessageConverters(ClientHttpResponse clientResponse, Runnable callback, Type bodyType, Class<T> bodyClass) {
private <T> T readWithMessageConverters(ClientHttpResponse clientResponse, Runnable callback, Type bodyType,
Class<T> bodyClass) {
MediaType contentType = getContentType(clientResponse);
try (clientResponse) {
callback.run();
IntrospectingClientHttpResponse responseWrapper = new IntrospectingClientHttpResponse(clientResponse);
if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
return null;
}
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter genericHttpMessageConverter) {
if (genericHttpMessageConverter.canRead(bodyType, null, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading to [" + ResolvableType.forType(bodyType) + "]");
}
return (T) genericHttpMessageConverter.read(bodyType, null, clientResponse);
return (T) genericHttpMessageConverter.read(bodyType, null, responseWrapper);
}
}
if (messageConverter.canRead(bodyClass, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading to [" + bodyClass.getName() + "] as \"" + contentType + "\"");
}
return (T) messageConverter.read((Class)bodyClass, clientResponse);
return (T) messageConverter.read((Class)bodyClass, responseWrapper);
}
}
throw new UnknownContentTypeException(bodyType, contentType,
clientResponse.getStatusCode(), clientResponse.getStatusText(),
clientResponse.getHeaders(), RestClientUtils.getBody(clientResponse));
responseWrapper.getStatusCode(), responseWrapper.getStatusText(),
responseWrapper.getHeaders(), RestClientUtils.getBody(responseWrapper));
}
catch (UncheckedIOException | IOException | HttpMessageNotReadableException ex) {
throw new RestClientException("Error while extracting response for type [" +
@ -585,11 +593,13 @@ final class DefaultRestClient implements RestClient {
}
@Override
@Nullable
public <T> T body(Class<T> bodyType) {
return readBody(bodyType, bodyType);
}
@Override
@Nullable
public <T> T body(ParameterizedTypeReference<T> bodyType) {
Type type = bodyType.getType();
Class<T> bodyClass = bodyClass(type);
@ -637,6 +647,7 @@ final class DefaultRestClient implements RestClient {
}
@Nullable
private <T> T readBody(Type bodyType, Class<T> bodyClass) {
return DefaultRestClient.this.readWithMessageConverters(this.clientResponse, this::applyStatusHandlers,
bodyType, bodyClass);

View File

@ -348,6 +348,23 @@ class RestClientIntegrationTests {
assertThat(result).isNull();
}
@ParameterizedRestClientTest
@SuppressWarnings({ "rawtypes", "unchecked" })
void retrieveJsonEmpty(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);
prepareResponse(response -> response
.setResponseCode(200)
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE));
Pojo result = this.restClient.get()
.uri("/null")
.retrieve()
.body(Pojo.class);
assertThat(result).isNull();
}
@ParameterizedRestClientTest
void retrieve404(ClientHttpRequestFactory requestFactory) {
startServer(requestFactory);