|
|
|
|
@ -206,8 +206,8 @@ final class DefaultRestClient implements RestClient {
@@ -206,8 +206,8 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
@SuppressWarnings({"rawtypes", "unchecked"}) |
|
|
|
|
private <T> T readWithMessageConverters(ClientHttpResponse clientResponse, Runnable callback, Type bodyType, |
|
|
|
|
Class<T> bodyClass, @Nullable Observation observation) { |
|
|
|
|
private <T> T readWithMessageConverters( |
|
|
|
|
ClientHttpResponse clientResponse, Runnable callback, Type bodyType, Class<T> bodyClass) { |
|
|
|
|
|
|
|
|
|
MediaType contentType = getContentType(clientResponse); |
|
|
|
|
|
|
|
|
|
@ -257,21 +257,8 @@ final class DefaultRestClient implements RestClient {
@@ -257,21 +257,8 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
else { |
|
|
|
|
cause = exc; |
|
|
|
|
} |
|
|
|
|
RestClientException restClientException = new RestClientException("Error while extracting response for type [" + |
|
|
|
|
throw new RestClientException("Error while extracting response for type [" + |
|
|
|
|
ResolvableType.forType(bodyType) + "] and content type [" + contentType + "]", cause); |
|
|
|
|
if (observation != null) { |
|
|
|
|
observation.error(restClientException); |
|
|
|
|
} |
|
|
|
|
throw restClientException; |
|
|
|
|
} |
|
|
|
|
catch (RestClientException restClientException) { |
|
|
|
|
if (observation != null) { |
|
|
|
|
observation.error(restClientException); |
|
|
|
|
} |
|
|
|
|
throw restClientException; |
|
|
|
|
} |
|
|
|
|
finally { |
|
|
|
|
clientResponse.close(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -536,14 +523,16 @@ final class DefaultRestClient implements RestClient {
@@ -536,14 +523,16 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public ResponseSpec retrieve() { |
|
|
|
|
return exchangeInternal(DefaultResponseSpec::new, false); |
|
|
|
|
return new DefaultResponseSpec(this); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
@Nullable |
|
|
|
|
public <T> T exchange(ExchangeFunction<T> exchangeFunction, boolean close) { |
|
|
|
|
return exchangeInternal(exchangeFunction, close); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
private <T> T exchangeInternal(ExchangeFunction<T> exchangeFunction, boolean close) { |
|
|
|
|
Assert.notNull(exchangeFunction, "ExchangeFunction must not be null"); |
|
|
|
|
|
|
|
|
|
@ -578,39 +567,31 @@ final class DefaultRestClient implements RestClient {
@@ -578,39 +567,31 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
} |
|
|
|
|
clientResponse = clientRequest.execute(); |
|
|
|
|
observationContext.setResponse(clientResponse); |
|
|
|
|
ConvertibleClientHttpResponse convertibleWrapper = new DefaultConvertibleClientHttpResponse(clientResponse, observation, observationScope); |
|
|
|
|
ConvertibleClientHttpResponse convertibleWrapper = new DefaultConvertibleClientHttpResponse(clientResponse); |
|
|
|
|
return exchangeFunction.exchange(clientRequest, convertibleWrapper); |
|
|
|
|
} |
|
|
|
|
catch (IOException ex) { |
|
|
|
|
ResourceAccessException resourceAccessException = createResourceAccessException(uri, this.httpMethod, ex); |
|
|
|
|
if (observationScope != null) { |
|
|
|
|
observationScope.close(); |
|
|
|
|
} |
|
|
|
|
if (observation != null) { |
|
|
|
|
observation.error(resourceAccessException); |
|
|
|
|
observation.stop(); |
|
|
|
|
} |
|
|
|
|
throw resourceAccessException; |
|
|
|
|
} |
|
|
|
|
catch (Throwable error) { |
|
|
|
|
if (observationScope != null) { |
|
|
|
|
observationScope.close(); |
|
|
|
|
} |
|
|
|
|
if (observation != null) { |
|
|
|
|
observation.error(error); |
|
|
|
|
observation.stop(); |
|
|
|
|
} |
|
|
|
|
throw error; |
|
|
|
|
} |
|
|
|
|
finally { |
|
|
|
|
if (observationScope != null) { |
|
|
|
|
observationScope.close(); |
|
|
|
|
} |
|
|
|
|
if (observation != null) { |
|
|
|
|
observation.stop(); |
|
|
|
|
} |
|
|
|
|
if (close && clientResponse != null) { |
|
|
|
|
clientResponse.close(); |
|
|
|
|
if (observationScope != null) { |
|
|
|
|
observationScope.close(); |
|
|
|
|
} |
|
|
|
|
if (observation != null) { |
|
|
|
|
observation.stop(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -719,17 +700,14 @@ final class DefaultRestClient implements RestClient {
@@ -719,17 +700,14 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
|
|
|
|
|
private class DefaultResponseSpec implements ResponseSpec { |
|
|
|
|
|
|
|
|
|
private final HttpRequest clientRequest; |
|
|
|
|
|
|
|
|
|
private final ClientHttpResponse clientResponse; |
|
|
|
|
private final RequestHeadersSpec<?> requestHeadersSpec; |
|
|
|
|
|
|
|
|
|
private final List<StatusHandler> statusHandlers = new ArrayList<>(1); |
|
|
|
|
|
|
|
|
|
private final int defaultStatusHandlerCount; |
|
|
|
|
|
|
|
|
|
DefaultResponseSpec(HttpRequest clientRequest, ClientHttpResponse clientResponse) { |
|
|
|
|
this.clientRequest = clientRequest; |
|
|
|
|
this.clientResponse = clientResponse; |
|
|
|
|
DefaultResponseSpec(RequestHeadersSpec<?> requestHeadersSpec) { |
|
|
|
|
this.requestHeadersSpec = requestHeadersSpec; |
|
|
|
|
this.statusHandlers.addAll(DefaultRestClient.this.defaultStatusHandlers); |
|
|
|
|
this.statusHandlers.add(StatusHandler.defaultHandler(DefaultRestClient.this.messageConverters)); |
|
|
|
|
this.defaultStatusHandlerCount = this.statusHandlers.size(); |
|
|
|
|
@ -761,7 +739,7 @@ final class DefaultRestClient implements RestClient {
@@ -761,7 +739,7 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
@Override |
|
|
|
|
@Nullable |
|
|
|
|
public <T> T body(Class<T> bodyType) { |
|
|
|
|
return readBody(bodyType, bodyType); |
|
|
|
|
return executeAndExtract((request, response) -> readBody(request, response, bodyType, bodyType)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
@ -769,7 +747,7 @@ final class DefaultRestClient implements RestClient {
@@ -769,7 +747,7 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
public <T> T body(ParameterizedTypeReference<T> bodyType) { |
|
|
|
|
Type type = bodyType.getType(); |
|
|
|
|
Class<T> bodyClass = bodyClass(type); |
|
|
|
|
return readBody(type, bodyClass); |
|
|
|
|
return executeAndExtract((request, response) -> readBody(request, response, type, bodyClass)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
@ -785,50 +763,64 @@ final class DefaultRestClient implements RestClient {
@@ -785,50 +763,64 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private <T> ResponseEntity<T> toEntityInternal(Type bodyType, Class<T> bodyClass) { |
|
|
|
|
T body = readBody(bodyType, bodyClass); |
|
|
|
|
try { |
|
|
|
|
return ResponseEntity.status(this.clientResponse.getStatusCode()) |
|
|
|
|
.headers(this.clientResponse.getHeaders()) |
|
|
|
|
.body(body); |
|
|
|
|
} |
|
|
|
|
catch (IOException ex) { |
|
|
|
|
throw new ResourceAccessException("Could not retrieve response status code: " + ex.getMessage(), ex); |
|
|
|
|
} |
|
|
|
|
ResponseEntity<T> entity = executeAndExtract((request, response) -> { |
|
|
|
|
T body = readBody(request, response, bodyType, bodyClass); |
|
|
|
|
try { |
|
|
|
|
return ResponseEntity.status(response.getStatusCode()) |
|
|
|
|
.headers(response.getHeaders()) |
|
|
|
|
.body(body); |
|
|
|
|
} |
|
|
|
|
catch (IOException ex) { |
|
|
|
|
throw new ResourceAccessException( |
|
|
|
|
"Could not retrieve response status code: " + ex.getMessage(), ex); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
Assert.state(entity != null, "No ResponseEntity"); |
|
|
|
|
return entity; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public ResponseEntity<Void> toBodilessEntity() { |
|
|
|
|
try (this.clientResponse) { |
|
|
|
|
applyStatusHandlers(); |
|
|
|
|
return ResponseEntity.status(this.clientResponse.getStatusCode()) |
|
|
|
|
.headers(this.clientResponse.getHeaders()) |
|
|
|
|
.build(); |
|
|
|
|
} |
|
|
|
|
catch (UncheckedIOException ex) { |
|
|
|
|
throw new ResourceAccessException("Could not retrieve response status code: " + ex.getMessage(), ex.getCause()); |
|
|
|
|
} |
|
|
|
|
catch (IOException ex) { |
|
|
|
|
throw new ResourceAccessException("Could not retrieve response status code: " + ex.getMessage(), ex); |
|
|
|
|
} |
|
|
|
|
ResponseEntity<Void> entity = executeAndExtract((request, response) -> { |
|
|
|
|
try (response) { |
|
|
|
|
applyStatusHandlers(request, response); |
|
|
|
|
return ResponseEntity.status(response.getStatusCode()) |
|
|
|
|
.headers(response.getHeaders()) |
|
|
|
|
.build(); |
|
|
|
|
} |
|
|
|
|
catch (UncheckedIOException ex) { |
|
|
|
|
throw new ResourceAccessException( |
|
|
|
|
"Could not retrieve response status code: " + ex.getMessage(), ex.getCause()); |
|
|
|
|
} |
|
|
|
|
catch (IOException ex) { |
|
|
|
|
throw new ResourceAccessException( |
|
|
|
|
"Could not retrieve response status code: " + ex.getMessage(), ex); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
Assert.state(entity != null, "No ResponseEntity"); |
|
|
|
|
return entity; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
public <T> T executeAndExtract(RequestHeadersSpec.ExchangeFunction<T> exchangeFunction) { |
|
|
|
|
return this.requestHeadersSpec.exchange(exchangeFunction); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
private <T> T readBody(Type bodyType, Class<T> bodyClass) { |
|
|
|
|
return DefaultRestClient.this.readWithMessageConverters(this.clientResponse, this::applyStatusHandlers, |
|
|
|
|
bodyType, bodyClass, getCurrentObservation()); |
|
|
|
|
private <T> T readBody(HttpRequest request, ClientHttpResponse response, Type bodyType, Class<T> bodyClass) { |
|
|
|
|
return DefaultRestClient.this.readWithMessageConverters( |
|
|
|
|
response, () -> applyStatusHandlers(request, response), bodyType, bodyClass); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void applyStatusHandlers() { |
|
|
|
|
private void applyStatusHandlers(HttpRequest request, ClientHttpResponse response) { |
|
|
|
|
try { |
|
|
|
|
ClientHttpResponse response = this.clientResponse; |
|
|
|
|
if (response instanceof DefaultConvertibleClientHttpResponse convertibleResponse) { |
|
|
|
|
response = convertibleResponse.delegate; |
|
|
|
|
} |
|
|
|
|
for (StatusHandler handler : this.statusHandlers) { |
|
|
|
|
if (handler.test(response)) { |
|
|
|
|
handler.handle(this.clientRequest, response); |
|
|
|
|
handler.handle(request, response); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@ -838,14 +830,6 @@ final class DefaultRestClient implements RestClient {
@@ -838,14 +830,6 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
private Observation getCurrentObservation() { |
|
|
|
|
if (this.clientResponse instanceof DefaultConvertibleClientHttpResponse convertibleResponse) { |
|
|
|
|
return convertibleResponse.observation; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -853,21 +837,14 @@ final class DefaultRestClient implements RestClient {
@@ -853,21 +837,14 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
|
|
|
|
|
private final ClientHttpResponse delegate; |
|
|
|
|
|
|
|
|
|
private final Observation observation; |
|
|
|
|
|
|
|
|
|
private final Observation.Scope observationScope; |
|
|
|
|
|
|
|
|
|
public DefaultConvertibleClientHttpResponse(ClientHttpResponse delegate, Observation observation, Observation.Scope observationScope) { |
|
|
|
|
public DefaultConvertibleClientHttpResponse(ClientHttpResponse delegate) { |
|
|
|
|
this.delegate = delegate; |
|
|
|
|
this.observation = observation; |
|
|
|
|
this.observationScope = observationScope; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
@Override |
|
|
|
|
public <T> T bodyTo(Class<T> bodyType) { |
|
|
|
|
return readWithMessageConverters(this.delegate, () -> {} , bodyType, bodyType, this.observation); |
|
|
|
|
return readWithMessageConverters(this.delegate, () -> {} , bodyType, bodyType); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Nullable |
|
|
|
|
@ -875,7 +852,7 @@ final class DefaultRestClient implements RestClient {
@@ -875,7 +852,7 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
public <T> T bodyTo(ParameterizedTypeReference<T> bodyType) { |
|
|
|
|
Type type = bodyType.getType(); |
|
|
|
|
Class<T> bodyClass = bodyClass(type); |
|
|
|
|
return readWithMessageConverters(this.delegate, () -> {}, type, bodyClass, this.observation); |
|
|
|
|
return readWithMessageConverters(this.delegate, () -> {}, type, bodyClass); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
@ -901,8 +878,6 @@ final class DefaultRestClient implements RestClient {
@@ -901,8 +878,6 @@ final class DefaultRestClient implements RestClient {
|
|
|
|
|
@Override |
|
|
|
|
public void close() { |
|
|
|
|
this.delegate.close(); |
|
|
|
|
this.observationScope.close(); |
|
|
|
|
this.observation.stop(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|