diff --git a/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java b/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java index c981159b60..d72efa9cbb 100644 --- a/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java +++ b/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java @@ -149,7 +149,7 @@ final class DefaultRestClient implements RestClient { @Override public RequestBodyUriSpec method(HttpMethod method) { - Assert.notNull(method, "Method must not be null"); + Assert.notNull(method, "HttpMethod must not be null"); return methodInternal(method); } @@ -450,7 +450,6 @@ final class DefaultRestClient implements RestClient { } - @FunctionalInterface private interface InternalBody { @@ -487,7 +486,7 @@ final class DefaultRestClient implements RestClient { @Override public ResponseSpec onStatus(ResponseErrorHandler errorHandler) { - Assert.notNull(errorHandler, "ErrorHandler must not be null"); + Assert.notNull(errorHandler, "ResponseErrorHandler must not be null"); return onStatusInternal(StatusHandler.fromErrorHandler(errorHandler)); } @@ -613,6 +612,6 @@ final class DefaultRestClient implements RestClient { } } - } + } diff --git a/spring-web/src/main/java/org/springframework/web/client/RestClient.java b/spring-web/src/main/java/org/springframework/web/client/RestClient.java index eedc1b2a79..25c41bd0cb 100644 --- a/spring-web/src/main/java/org/springframework/web/client/RestClient.java +++ b/spring-web/src/main/java/org/springframework/web/client/RestClient.java @@ -61,11 +61,12 @@ import org.springframework.web.util.UriBuilderFactory; *
  • {@link RequestHeadersSpec#retrieve() retrieve()} *
  • {@link RequestHeadersSpec#exchange(RequestHeadersSpec.ExchangeFunction) exchange(Function<ClientHttpRequest, T>)} * + * *

    For examples with a request body see: *

    * * @author Arjen Poutsma @@ -218,7 +219,8 @@ public interface RestClient { * for a given URL is absolute in which case the base URL is ignored. *

    Note: this method is mutually exclusive with * {@link #uriBuilderFactory(UriBuilderFactory)}. If both are used, the - * baseUrl value provided here will be ignored. + * {@code baseUrl} value provided here will be ignored. + * @return this builder * @see DefaultUriBuilderFactory#DefaultUriBuilderFactory(String) * @see #uriBuilderFactory(UriBuilderFactory) */ @@ -236,7 +238,8 @@ public interface RestClient { * *

    Note: this method is mutually exclusive with * {@link #uriBuilderFactory(UriBuilderFactory)}. If both are used, the - * defaultUriVariables value provided here will be ignored. + * {@code defaultUriVariables} value provided here will be ignored. + * @return this builder * @see DefaultUriBuilderFactory#setDefaultUriVariables(Map) * @see #uriBuilderFactory(UriBuilderFactory) */ @@ -251,6 +254,7 @@ public interface RestClient { *

  • {@link #defaultUriVariables(Map)}. * * @param uriBuilderFactory the URI builder factory to use + * @return this builder * @see #baseUrl(String) * @see #defaultUriVariables(Map) */ @@ -261,19 +265,22 @@ public interface RestClient { * if the request does not already contain such a header. * @param header the header name * @param values the header values + * @return this builder */ Builder defaultHeader(String header, String... values); /** - * Provides access to every {@link #defaultHeader(String, String...)} - * declared so far with the possibility to add, replace, or remove. + * Provide a consumer to access to every {@linkplain #defaultHeader(String, String...) + * default header} declared so far, with the possibility to add, replace, or remove. * @param headersConsumer the consumer + * @return this builder */ Builder defaultHeaders(Consumer headersConsumer); /** * Provide a consumer to customize every request being built. * @param defaultRequest the consumer to use for modifying requests + * @return this builder */ Builder defaultRequest(Consumer> defaultRequest); @@ -306,6 +313,7 @@ public interface RestClient { /** * Add the given request interceptor to the end of the interceptor chain. * @param interceptor the interceptor to be added to the chain + * @return this builder */ Builder requestInterceptor(ClientHttpRequestInterceptor interceptor); @@ -321,6 +329,7 @@ public interface RestClient { /** * Add the given request initializer to the end of the initializer chain. * @param initializer the initializer to be added to the chain + * @return this builder */ Builder requestInitializer(ClientHttpRequestInitializer initializer); @@ -338,12 +347,14 @@ public interface RestClient { * for plugging in and/or customizing options of the underlying HTTP * client library (e.g. SSL). * @param requestFactory the request factory to use + * @return this builder */ Builder requestFactory(ClientHttpRequestFactory requestFactory); /** * Configure the message converters for the {@code RestClient} to use. * @param configurer the configurer to apply + * @return this builder */ Builder messageConverters(Consumer>> configurer); @@ -351,6 +362,7 @@ public interface RestClient { * Apply the given {@code Consumer} to this builder instance. *

    This can be useful for applying pre-packaged customizations. * @param builderConsumer the consumer to apply + * @return this builder */ Builder apply(Consumer builderConsumer); @@ -379,14 +391,14 @@ public interface RestClient { /** * Specify the URI for the request using a URI template and URI variables. - * If a {@link UriBuilderFactory} was configured for the client (e.g. + *

    If a {@link UriBuilderFactory} was configured for the client (e.g. * with a base URI) it will be used to expand the URI template. */ S uri(String uri, Object... uriVariables); /** * Specify the URI for the request using a URI template and URI variables. - * If a {@link UriBuilderFactory} was configured for the client (e.g. + *

    If a {@link UriBuilderFactory} was configured for the client (e.g. * with a base URI) it will be used to expand the URI template. */ S uri(String uri, Map uriVariables); @@ -478,11 +490,11 @@ public interface RestClient { /** * Callback for access to the {@link ClientHttpRequest} that in turn * provides access to the native request of the underlying HTTP library. - * This could be useful for setting advanced, per-request options that - * exposed by the underlying library. + *

    This could be useful for setting advanced, per-request options that + * are exposed by the underlying library. * @param requestConsumer a consumer to access the * {@code ClientHttpRequest} with - * @return {@code ResponseSpec} to specify how to decode the body + * @return this builder */ S httpRequest(Consumer requestConsumer); @@ -508,6 +520,7 @@ public interface RestClient { * {@link HttpClientErrorException} and 5xx response codes in a * {@link HttpServerErrorException}. To customize error handling, use * {@link ResponseSpec#onStatus(Predicate, ResponseSpec.ErrorHandler) onStatus} handlers. + * @return {@code ResponseSpec} to specify how to decode the body */ ResponseSpec retrieve(); diff --git a/spring-web/src/main/java/org/springframework/web/client/StatusHandler.java b/spring-web/src/main/java/org/springframework/web/client/StatusHandler.java index 5083861103..2b2f7ea8f6 100644 --- a/spring-web/src/main/java/org/springframework/web/client/StatusHandler.java +++ b/spring-web/src/main/java/org/springframework/web/client/StatusHandler.java @@ -65,7 +65,7 @@ final class StatusHandler { } public static StatusHandler fromErrorHandler(ResponseErrorHandler errorHandler) { - Assert.notNull(errorHandler, "ErrorHandler must not be null"); + Assert.notNull(errorHandler, "ResponseErrorHandler must not be null"); return new StatusHandler(errorHandler::hasError, (request, response) -> errorHandler.handleError(request.getURI(), request.getMethod(), response)); @@ -73,29 +73,29 @@ final class StatusHandler { public static StatusHandler defaultHandler(List> messageConverters) { return new StatusHandler(response -> response.getStatusCode().isError(), - (request, response) -> { - HttpStatusCode statusCode = response.getStatusCode(); - String statusText = response.getStatusText(); - HttpHeaders headers = response.getHeaders(); - byte[] body = RestClientUtils.getBody(response); - Charset charset = RestClientUtils.getCharset(response); - String message = getErrorMessage(statusCode.value(), statusText, body, charset); - RestClientResponseException ex; + (request, response) -> { + HttpStatusCode statusCode = response.getStatusCode(); + String statusText = response.getStatusText(); + HttpHeaders headers = response.getHeaders(); + byte[] body = RestClientUtils.getBody(response); + Charset charset = RestClientUtils.getCharset(response); + String message = getErrorMessage(statusCode.value(), statusText, body, charset); + RestClientResponseException ex; - if (statusCode.is4xxClientError()) { - ex = HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset); - } - else if (statusCode.is5xxServerError()) { - ex = HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset); - } - else { - ex = new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset); - } - if (!CollectionUtils.isEmpty(messageConverters)) { - ex.setBodyConvertFunction(initBodyConvertFunction(response, body, messageConverters)); - } - throw ex; - }); + if (statusCode.is4xxClientError()) { + ex = HttpClientErrorException.create(message, statusCode, statusText, headers, body, charset); + } + else if (statusCode.is5xxServerError()) { + ex = HttpServerErrorException.create(message, statusCode, statusText, headers, body, charset); + } + else { + ex = new UnknownHttpStatusCodeException(message, statusCode.value(), statusText, headers, body, charset); + } + if (!CollectionUtils.isEmpty(messageConverters)) { + ex.setBodyConvertFunction(initBodyConvertFunction(response, body, messageConverters)); + } + throw ex; + }); } private static Function initBodyConvertFunction(ClientHttpResponse response, byte[] body, List> messageConverters) { diff --git a/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java b/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java index 35ebf7376a..f681c8617b 100644 --- a/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java +++ b/spring-web/src/test/java/org/springframework/web/client/RestClientIntegrationTests.java @@ -68,7 +68,7 @@ class RestClientIntegrationTests { @Target(ElementType.METHOD) @ParameterizedTest(name = "[{index}] {0}") @MethodSource("clientHttpRequestFactories") - @interface ParameterizedWebClientTest { + @interface ParameterizedRestClientTest { } static Stream> clientHttpRequestFactories() { @@ -104,7 +104,7 @@ class RestClientIntegrationTests { } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieve(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -126,7 +126,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieveJson(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -150,7 +150,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieveJsonWithParameterizedTypeReference(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -175,7 +175,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieveJsonAsResponseEntity(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -200,7 +200,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieveJsonAsBodilessEntity(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -224,7 +224,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieveJsonArray(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -251,7 +251,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieveJsonArrayAsResponseEntityList(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -280,7 +280,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieveJsonAsSerializedText(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -302,8 +302,8 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest - @SuppressWarnings("rawtypes") + @ParameterizedRestClientTest + @SuppressWarnings({ "rawtypes", "unchecked" }) void retrieveJsonNull(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -320,7 +320,7 @@ class RestClientIntegrationTests { assertThat(result).isNull(); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieve404(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -338,7 +338,7 @@ class RestClientIntegrationTests { } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieve404WithBody(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -356,7 +356,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting")); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieve500(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -383,7 +383,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getPath()).isEqualTo(path)); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieve500AsEntity(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -404,7 +404,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieve500AsBodilessEntity(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -425,7 +425,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void retrieve555UnknownStatus(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -454,7 +454,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getPath()).isEqualTo("/unknownPage")); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void postPojoAsJson(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -477,13 +477,12 @@ class RestClientIntegrationTests { expectRequest(request -> { assertThat(request.getPath()).isEqualTo("/pojo/capitalize"); assertThat(request.getBody().readUtf8()).isEqualTo("{\"foo\":\"foofoo\",\"bar\":\"barbar\"}"); -// assertThat(request.getHeader(HttpHeaders.CONTENT_LENGTH)).isEqualTo("31"); assertThat(request.getHeader(HttpHeaders.ACCEPT)).isEqualTo("application/json"); assertThat(request.getHeader(HttpHeaders.CONTENT_TYPE)).isEqualTo("application/json"); }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void statusHandler(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -504,7 +503,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting")); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void statusHandlerParameterizedTypeReference(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -526,7 +525,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting")); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void statusHandlerSuppressedErrorSignal(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -545,7 +544,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting")); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void statusHandlerSuppressedErrorSignalWithEntity(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -570,7 +569,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void exchangeForPlainText(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -590,7 +589,7 @@ class RestClientIntegrationTests { }); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void exchangeFor404(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -607,7 +606,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getPath()).isEqualTo("/greeting")); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void requestInitializer(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -629,7 +628,7 @@ class RestClientIntegrationTests { expectRequest(request -> assertThat(request.getHeader("foo")).isEqualTo("bar")); } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void requestInterceptor(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -656,7 +655,7 @@ class RestClientIntegrationTests { } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void filterForErrorHandling(ClientHttpRequestFactory requestFactory) { startServer(requestFactory); @@ -700,7 +699,7 @@ class RestClientIntegrationTests { } - @ParameterizedWebClientTest + @ParameterizedRestClientTest void invalidDomain(ClientHttpRequestFactory requestFactory) { startServer(requestFactory);