Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@ final class DefaultRestClient implements RestClient {

private final List<StatusHandler> defaultStatusHandlers;

private final boolean defaultStatusHandlerEnabled;

private final DefaultRestClientBuilder builder;

private final List<HttpMessageConverter<?>> messageConverters;
Expand All @@ -134,7 +136,7 @@ final class DefaultRestClient implements RestClient {
@Nullable MultiValueMap<String, String> defaultCookies,
@Nullable Object defaultApiVersion, @Nullable ApiVersionInserter apiVersionInserter,
@Nullable Consumer<RequestHeadersSpec<?>> defaultRequest,
@Nullable List<StatusHandler> statusHandlers,
@Nullable List<StatusHandler> statusHandlers, boolean defaultStatusHandlerEnabled,
List<HttpMessageConverter<?>> messageConverters,
ObservationRegistry observationRegistry,
@Nullable ClientRequestObservationConvention observationConvention,
Expand All @@ -151,6 +153,7 @@ final class DefaultRestClient implements RestClient {
this.apiVersionInserter = apiVersionInserter;
this.defaultRequest = defaultRequest;
this.defaultStatusHandlers = (statusHandlers != null ? new ArrayList<>(statusHandlers) : new ArrayList<>());
this.defaultStatusHandlerEnabled = defaultStatusHandlerEnabled;
this.messageConverters = messageConverters;
this.observationRegistry = observationRegistry;
this.observationConvention = observationConvention;
Expand Down Expand Up @@ -785,7 +788,9 @@ private class DefaultResponseSpec implements ResponseSpec {
DefaultResponseSpec(RequestHeadersSpec<?> requestHeadersSpec) {
this.requestHeadersSpec = requestHeadersSpec;
this.statusHandlers.addAll(DefaultRestClient.this.defaultStatusHandlers);
this.statusHandlers.add(StatusHandler.createDefaultStatusHandler(DefaultRestClient.this.messageConverters));
if (DefaultRestClient.this.defaultStatusHandlerEnabled) {
this.statusHandlers.add(StatusHandler.createDefaultStatusHandler(DefaultRestClient.this.messageConverters));
}
this.defaultStatusHandlerCount = this.statusHandlers.size();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ final class DefaultRestClientBuilder implements RestClient.Builder {

private @Nullable List<StatusHandler> statusHandlers;

private boolean defaultStatusHandlerEnabled = true;

private @Nullable List<ClientHttpRequestInterceptor> interceptors;

private @Nullable BiPredicate<URI, HttpMethod> bufferingPredicate;
Expand Down Expand Up @@ -138,6 +140,7 @@ public DefaultRestClientBuilder(DefaultRestClientBuilder other) {
this.apiVersionInserter = other.apiVersionInserter;
this.defaultRequest = other.defaultRequest;
this.statusHandlers = (other.statusHandlers != null ? new ArrayList<>(other.statusHandlers) : null);
this.defaultStatusHandlerEnabled = other.defaultStatusHandlerEnabled;
this.interceptors = (other.interceptors != null) ? new ArrayList<>(other.interceptors) : null;
this.bufferingPredicate = other.bufferingPredicate;
this.initializers = (other.initializers != null) ? new ArrayList<>(other.initializers) : null;
Expand Down Expand Up @@ -301,6 +304,12 @@ public RestClient.Builder defaultStatusHandler(ResponseErrorHandler errorHandler
return defaultStatusHandlerInternal(StatusHandler.fromErrorHandler(errorHandler));
}

@Override
public RestClient.Builder disableDefaultStatusHandler() {
this.defaultStatusHandlerEnabled = false;
return this;
}

private RestClient.Builder defaultStatusHandlerInternal(StatusHandler statusHandler) {
if (this.statusHandlers == null) {
this.statusHandlers = new ArrayList<>();
Expand Down Expand Up @@ -436,7 +445,7 @@ public RestClient build() {
requestFactory, this.interceptors, this.bufferingPredicate, this.initializers,
uriBuilderFactory, defaultHeaders, defaultCookies, this.defaultApiVersion,
this.apiVersionInserter, this.defaultRequest,
this.statusHandlers, converters,
this.statusHandlers, this.defaultStatusHandlerEnabled, converters,
this.observationRegistry, this.observationConvention,
new DefaultRestClientBuilder(this));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
* <p>This implementation is not suitable with the {@link RestClient} as it uses
* a list of candidates where the first matching is invoked. If you want to
* disable default status handlers with the {@code RestClient}, consider
* disabling the built-in default status handler via
* {@link RestClient.Builder#disableDefaultStatusHandler()} or
* registering a noop {@link ResponseSpec.ErrorHandler ErrorHandler} with a
* predicate that matches all status code, see
* {@link RestClient.Builder#defaultStatusHandler(Predicate, ErrorHandler)}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,12 +386,25 @@ Builder defaultStatusHandler(Predicate<HttpStatusCode> statusPredicate,
* error is invoked. If you want to disable other defaults, consider
* using {@link #defaultStatusHandler(Predicate, ResponseSpec.ErrorHandler)}
* with a predicate that matches all status codes.
* <p>To disable the built-in default status handler entirely, use
* {@link #disableDefaultStatusHandler()}.
* @param errorHandler handler that typically, though not necessarily,
* throws an exception
* @return this builder
*/
Builder defaultStatusHandler(ResponseErrorHandler errorHandler);

/**
* Disable the default status handler that maps error status
* codes (4xx/5xx) to {@link RestClientException} variants.
* <p>By default, the default status handler is enabled. Disabling it allows
* full control over status handling via custom handlers or per-response
* {@code onStatus} registrations.
* @return this builder
* @since 7.0.4
*/
Builder disableDefaultStatusHandler();

/**
* Add the given request interceptor to the end of the interceptor chain.
* @param interceptor the interceptor to be added to the chain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;

Expand Down Expand Up @@ -117,6 +118,38 @@ void requiredBodyWithParameterizedTypeReferenceAndNullBody() throws IOException
);
}

@Test
void defaultStatusHandlerThrowsOnErrorStatus() throws IOException {
mockSentRequest(HttpMethod.GET, "https://example.org");
mockResponseStatus(HttpStatus.BAD_REQUEST);
mockResponseBody("Error", MediaType.TEXT_PLAIN);

assertThatThrownBy(() -> this.client.get()
.uri("https://example.org")
.retrieve()
.body(String.class))
.isInstanceOf(HttpClientErrorException.class);
}

@Test
void disableDefaultStatusHandlerAllowsErrorBody() throws IOException {
this.client = RestClient.builder()
.requestFactory(this.requestFactory)
.disableDefaultStatusHandler()
.build();

mockSentRequest(HttpMethod.GET, "https://example.org");
mockResponseStatus(HttpStatus.BAD_REQUEST);
mockResponseBody("Error", MediaType.TEXT_PLAIN);

String result = this.client.get()
.uri("https://example.org")
.retrieve()
.body(String.class);

assertThat(result).isEqualTo("Error");
}


private void mockSentRequest(HttpMethod method, String uri) throws IOException {
given(this.requestFactory.createRequest(URI.create(uri), method)).willReturn(this.request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,15 @@ void buildCopiesDefaultCookiesImmutable() {
);
}

@Test
void disableDefaultStatusHandler() {
RestClient restClient = RestClient.builder()
.disableDefaultStatusHandler()
.build();

assertThat(fieldValue("defaultStatusHandlerEnabled", restClient)).isEqualTo(false);
}

private static @Nullable Object fieldValue(String name, DefaultRestClientBuilder instance) {
try {
Field field = DefaultRestClientBuilder.class.getDeclaredField(name);
Expand Down