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:
parent
0dbb0f5c14
commit
d204dd2dbe
|
@ -184,32 +184,40 @@ final class DefaultRestClient implements RestClient {
|
||||||
return new DefaultRestClientBuilder(this.builder);
|
return new DefaultRestClientBuilder(this.builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
@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);
|
MediaType contentType = getContentType(clientResponse);
|
||||||
|
|
||||||
try (clientResponse) {
|
try (clientResponse) {
|
||||||
callback.run();
|
callback.run();
|
||||||
|
|
||||||
|
IntrospectingClientHttpResponse responseWrapper = new IntrospectingClientHttpResponse(clientResponse);
|
||||||
|
if (!responseWrapper.hasMessageBody() || responseWrapper.hasEmptyMessageBody()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
|
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
|
||||||
if (messageConverter instanceof GenericHttpMessageConverter genericHttpMessageConverter) {
|
if (messageConverter instanceof GenericHttpMessageConverter genericHttpMessageConverter) {
|
||||||
if (genericHttpMessageConverter.canRead(bodyType, null, contentType)) {
|
if (genericHttpMessageConverter.canRead(bodyType, null, contentType)) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Reading to [" + ResolvableType.forType(bodyType) + "]");
|
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 (messageConverter.canRead(bodyClass, contentType)) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Reading to [" + bodyClass.getName() + "] as \"" + contentType + "\"");
|
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,
|
throw new UnknownContentTypeException(bodyType, contentType,
|
||||||
clientResponse.getStatusCode(), clientResponse.getStatusText(),
|
responseWrapper.getStatusCode(), responseWrapper.getStatusText(),
|
||||||
clientResponse.getHeaders(), RestClientUtils.getBody(clientResponse));
|
responseWrapper.getHeaders(), RestClientUtils.getBody(responseWrapper));
|
||||||
}
|
}
|
||||||
catch (UncheckedIOException | IOException | HttpMessageNotReadableException ex) {
|
catch (UncheckedIOException | IOException | HttpMessageNotReadableException ex) {
|
||||||
throw new RestClientException("Error while extracting response for type [" +
|
throw new RestClientException("Error while extracting response for type [" +
|
||||||
|
@ -585,11 +593,13 @@ final class DefaultRestClient implements RestClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public <T> T body(Class<T> bodyType) {
|
public <T> T body(Class<T> bodyType) {
|
||||||
return readBody(bodyType, bodyType);
|
return readBody(bodyType, bodyType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@Nullable
|
||||||
public <T> T body(ParameterizedTypeReference<T> bodyType) {
|
public <T> T body(ParameterizedTypeReference<T> bodyType) {
|
||||||
Type type = bodyType.getType();
|
Type type = bodyType.getType();
|
||||||
Class<T> bodyClass = bodyClass(type);
|
Class<T> bodyClass = bodyClass(type);
|
||||||
|
@ -637,6 +647,7 @@ final class DefaultRestClient implements RestClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private <T> T readBody(Type bodyType, Class<T> bodyClass) {
|
private <T> T readBody(Type bodyType, Class<T> bodyClass) {
|
||||||
return DefaultRestClient.this.readWithMessageConverters(this.clientResponse, this::applyStatusHandlers,
|
return DefaultRestClient.this.readWithMessageConverters(this.clientResponse, this::applyStatusHandlers,
|
||||||
bodyType, bodyClass);
|
bodyType, bodyClass);
|
||||||
|
|
|
@ -348,6 +348,23 @@ class RestClientIntegrationTests {
|
||||||
assertThat(result).isNull();
|
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
|
@ParameterizedRestClientTest
|
||||||
void retrieve404(ClientHttpRequestFactory requestFactory) {
|
void retrieve404(ClientHttpRequestFactory requestFactory) {
|
||||||
startServer(requestFactory);
|
startServer(requestFactory);
|
||||||
|
|
Loading…
Reference in New Issue