Simplify use of InputStream with RestClient

Closes gh-36380
This commit is contained in:
rstoyanchev
2026-02-25 12:43:19 +00:00
parent 0c9127d111
commit e58ba2c665
3 changed files with 34 additions and 30 deletions
@@ -42,6 +42,7 @@ import org.jspecify.annotations.Nullable;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpRequest;
@@ -253,6 +254,10 @@ final class DefaultRestClient implements RestClient {
}
}
if (bodyClass.equals(InputStream.class)) {
return (T) responseWrapper.getBody();
}
throw new UnknownContentTypeException(bodyType, contentType,
responseWrapper.getStatusCode(), responseWrapper.getStatusText(),
responseWrapper.getHeaders(), RestClientUtils.getBody(responseWrapper));
@@ -609,7 +614,11 @@ final class DefaultRestClient implements RestClient {
clientResponse = clientRequest.execute();
observationContext.setResponse(clientResponse);
ConvertibleClientHttpResponse convertibleWrapper = new DefaultConvertibleClientHttpResponse(clientResponse, this.hints);
return exchangeFunction.exchange(clientRequest, convertibleWrapper);
T result = exchangeFunction.exchange(clientRequest, convertibleWrapper);
if (close && isStreamingResult(result)) {
close = false;
}
return result;
}
catch (IOException ex) {
ResourceAccessException resourceAccessException = createResourceAccessException(uri, this.httpMethod, ex);
@@ -746,6 +755,10 @@ final class DefaultRestClient implements RestClient {
return request;
}
private static boolean isStreamingResult(@Nullable Object result) {
return (result instanceof InputStream || result instanceof InputStreamResource);
}
private static ResourceAccessException createResourceAccessException(URI url, HttpMethod method, IOException ex) {
StringBuilder msg = new StringBuilder("I/O error on ");
msg.append(method.name());
@@ -16,8 +16,6 @@
package org.springframework.web.client.support;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
@@ -75,8 +73,7 @@ public final class RestClientAdapter implements HttpExchangeAdapter {
@Override
public <T> @Nullable T exchangeForBody(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
return (bodyType.getType().equals(InputStream.class) ?
exchangeForInputStream(values) : newRequest(values).retrieve().body(bodyType));
return newRequest(values).retrieve().body(bodyType);
}
@Override
@@ -86,21 +83,7 @@ public final class RestClientAdapter implements HttpExchangeAdapter {
@Override
public <T> ResponseEntity<T> exchangeForEntity(HttpRequestValues values, ParameterizedTypeReference<T> bodyType) {
return (bodyType.getType().equals(InputStream.class) ?
exchangeForEntityInputStream(values) : newRequest(values).retrieve().toEntity(bodyType));
}
@SuppressWarnings("unchecked")
private <T> T exchangeForInputStream(HttpRequestValues values) {
return (T) newRequest(values).exchange((request, response) -> getInputStream(response), false);
}
@SuppressWarnings("unchecked")
private <T> ResponseEntity<T> exchangeForEntityInputStream(HttpRequestValues values) {
return (ResponseEntity<T>) newRequest(values).exchangeForRequiredValue((request, response) ->
ResponseEntity.status(response.getStatusCode())
.headers(response.getHeaders())
.body(getInputStream(response)), false);
return newRequest(values).retrieve().toEntity(bodyType);
}
@SuppressWarnings("unchecked")
@@ -162,16 +145,6 @@ public final class RestClientAdapter implements HttpExchangeAdapter {
return bodySpec;
}
private static InputStream getInputStream(
RestClient.RequestHeadersSpec.ConvertibleClientHttpResponse response) throws IOException {
if (response.getStatusCode().isError()) {
throw response.createException();
}
return response.getBody();
}
/**
* Create a {@link RestClientAdapter} for the given {@link RestClient}.