Remove use of WebClient#exchange from WebTestClient

The exchange() method is now deprecated because it is not safe for
general use but that doesn't apply to the WebTestClient because it
exposes a different higher level API for response handling that
ensures the response is consumed. Nevertheless WebTestClient cannot
call WebClient.exchange() any more.

To fix this WebTestClient no longer delegates to WebClient and thus
gains direct access to the underlying ExchangeFunction. This is
not a big deal because WebClient and WebTestClient do the same
only when it comes to gathering builder options and request input.

See gh-25751
This commit is contained in:
Rossen Stoyanchev
2020-09-25 16:41:26 +01:00
parent 1404dd768f
commit db9190e0e6
6 changed files with 351 additions and 127 deletions

View File

@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@@ -46,12 +47,17 @@ import org.springframework.test.util.AssertionErrors;
import org.springframework.test.util.JsonExpectationsHelper;
import org.springframework.test.util.XmlExpectationsHelper;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MimeType;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.BodyInserter;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.ClientRequest;
import org.springframework.web.reactive.function.client.ClientResponse;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.util.UriBuilder;
import org.springframework.web.util.UriBuilderFactory;
/**
* Default implementation of {@link WebTestClient}.
@@ -61,30 +67,42 @@ import org.springframework.web.util.UriBuilder;
*/
class DefaultWebTestClient implements WebTestClient {
private final WebClient webClient;
private final WiretapConnector wiretapConnector;
private final Duration timeout;
private final ExchangeFunction exchangeFunction;
private final UriBuilderFactory uriBuilderFactory;
@Nullable
private final HttpHeaders defaultHeaders;
@Nullable
private final MultiValueMap<String, String> defaultCookies;
private final Duration responseTimeout;
private final DefaultWebTestClientBuilder builder;
private final AtomicLong requestIndex = new AtomicLong();
DefaultWebTestClient(WebClient.Builder clientBuilder, ClientHttpConnector connector,
@Nullable Duration timeout, DefaultWebTestClientBuilder webTestClientBuilder) {
DefaultWebTestClient(ClientHttpConnector connector,
Function<ClientHttpConnector, ExchangeFunction> exchangeFactory, UriBuilderFactory uriBuilderFactory,
@Nullable HttpHeaders headers, @Nullable MultiValueMap<String, String> cookies,
@Nullable Duration responseTimeout, DefaultWebTestClientBuilder clientBuilder) {
Assert.notNull(clientBuilder, "WebClient.Builder is required");
this.wiretapConnector = new WiretapConnector(connector);
this.webClient = clientBuilder.clientConnector(this.wiretapConnector).build();
this.timeout = (timeout != null ? timeout : Duration.ofSeconds(5));
this.builder = webTestClientBuilder;
this.exchangeFunction = exchangeFactory.apply(this.wiretapConnector);
this.uriBuilderFactory = uriBuilderFactory;
this.defaultHeaders = headers;
this.defaultCookies = cookies;
this.responseTimeout = (responseTimeout != null ? responseTimeout : Duration.ofSeconds(5));
this.builder = clientBuilder;
}
private Duration getTimeout() {
return this.timeout;
private Duration getResponseTimeout() {
return this.responseTimeout;
}
@@ -124,12 +142,12 @@ class DefaultWebTestClient implements WebTestClient {
}
@Override
public RequestBodyUriSpec method(HttpMethod method) {
return methodInternal(method);
public RequestBodyUriSpec method(HttpMethod httpMethod) {
return methodInternal(httpMethod);
}
private RequestBodyUriSpec methodInternal(HttpMethod method) {
return new DefaultRequestBodyUriSpec(this.webClient.method(method));
private RequestBodyUriSpec methodInternal(HttpMethod httpMethod) {
return new DefaultRequestBodyUriSpec(httpMethod);
}
@Override
@@ -145,154 +163,180 @@ class DefaultWebTestClient implements WebTestClient {
private class DefaultRequestBodyUriSpec implements RequestBodyUriSpec {
private final WebClient.RequestBodyUriSpec bodySpec;
private final HttpMethod httpMethod;
@Nullable
private URI uri;
private final HttpHeaders headers;
@Nullable
private MultiValueMap<String, String> cookies;
@Nullable
private BodyInserter<?, ? super ClientHttpRequest> inserter;
private final Map<String, Object> attributes = new LinkedHashMap<>(4);
@Nullable
private Consumer<ClientHttpRequest> httpRequestConsumer;
@Nullable
private String uriTemplate;
private final String requestId;
DefaultRequestBodyUriSpec(WebClient.RequestBodyUriSpec spec) {
this.bodySpec = spec;
DefaultRequestBodyUriSpec(HttpMethod httpMethod) {
this.httpMethod = httpMethod;
this.requestId = String.valueOf(requestIndex.incrementAndGet());
this.bodySpec.header(WebTestClient.WEBTESTCLIENT_REQUEST_ID, this.requestId);
this.headers = new HttpHeaders();
this.headers.add(WebTestClient.WEBTESTCLIENT_REQUEST_ID, this.requestId);
}
@Override
public RequestBodySpec uri(String uriTemplate, Object... uriVariables) {
this.bodySpec.uri(uriTemplate, uriVariables);
this.uriTemplate = uriTemplate;
return this;
return uri(uriBuilderFactory.expand(uriTemplate, uriVariables));
}
@Override
public RequestBodySpec uri(String uriTemplate, Map<String, ?> uriVariables) {
this.bodySpec.uri(uriTemplate, uriVariables);
this.uriTemplate = uriTemplate;
return this;
return uri(uriBuilderFactory.expand(uriTemplate, uriVariables));
}
@Override
public RequestBodySpec uri(Function<UriBuilder, URI> uriFunction) {
this.bodySpec.uri(uriFunction);
this.uriTemplate = null;
return this;
return uri(uriFunction.apply(uriBuilderFactory.builder()));
}
@Override
public RequestBodySpec uri(URI uri) {
this.bodySpec.uri(uri);
this.uriTemplate = null;
this.uri = uri;
return this;
}
private HttpHeaders getHeaders() {
return this.headers;
}
private MultiValueMap<String, String> getCookies() {
if (this.cookies == null) {
this.cookies = new LinkedMultiValueMap<>(3);
}
return this.cookies;
}
@Override
public RequestBodySpec header(String headerName, String... headerValues) {
this.bodySpec.header(headerName, headerValues);
for (String headerValue : headerValues) {
getHeaders().add(headerName, headerValue);
}
return this;
}
@Override
public RequestBodySpec headers(Consumer<HttpHeaders> headersConsumer) {
this.bodySpec.headers(headersConsumer);
headersConsumer.accept(getHeaders());
return this;
}
@Override
public RequestBodySpec attribute(String name, Object value) {
this.bodySpec.attribute(name, value);
this.attributes.put(name, value);
return this;
}
@Override
public RequestBodySpec attributes(
Consumer<Map<String, Object>> attributesConsumer) {
this.bodySpec.attributes(attributesConsumer);
public RequestBodySpec attributes(Consumer<Map<String, Object>> attributesConsumer) {
attributesConsumer.accept(this.attributes);
return this;
}
@Override
public RequestBodySpec accept(MediaType... acceptableMediaTypes) {
this.bodySpec.accept(acceptableMediaTypes);
getHeaders().setAccept(Arrays.asList(acceptableMediaTypes));
return this;
}
@Override
public RequestBodySpec acceptCharset(Charset... acceptableCharsets) {
this.bodySpec.acceptCharset(acceptableCharsets);
getHeaders().setAcceptCharset(Arrays.asList(acceptableCharsets));
return this;
}
@Override
public RequestBodySpec contentType(MediaType contentType) {
this.bodySpec.contentType(contentType);
getHeaders().setContentType(contentType);
return this;
}
@Override
public RequestBodySpec contentLength(long contentLength) {
this.bodySpec.contentLength(contentLength);
getHeaders().setContentLength(contentLength);
return this;
}
@Override
public RequestBodySpec cookie(String name, String value) {
this.bodySpec.cookie(name, value);
getCookies().add(name, value);
return this;
}
@Override
public RequestBodySpec cookies(
Consumer<MultiValueMap<String, String>> cookiesConsumer) {
this.bodySpec.cookies(cookiesConsumer);
public RequestBodySpec cookies(Consumer<MultiValueMap<String, String>> cookiesConsumer) {
cookiesConsumer.accept(getCookies());
return this;
}
@Override
public RequestBodySpec ifModifiedSince(ZonedDateTime ifModifiedSince) {
this.bodySpec.ifModifiedSince(ifModifiedSince);
getHeaders().setIfModifiedSince(ifModifiedSince);
return this;
}
@Override
public RequestBodySpec ifNoneMatch(String... ifNoneMatches) {
this.bodySpec.ifNoneMatch(ifNoneMatches);
getHeaders().setIfNoneMatch(Arrays.asList(ifNoneMatches));
return this;
}
@Override
public RequestHeadersSpec<?> bodyValue(Object body) {
this.bodySpec.bodyValue(body);
this.inserter = BodyInserters.fromValue(body);
return this;
}
@Override
public <T, S extends Publisher<T>> RequestHeadersSpec<?> body(S publisher, Class<T> elementClass) {
this.bodySpec.body(publisher, elementClass);
public <T, P extends Publisher<T>> RequestHeadersSpec<?> body(
P publisher, ParameterizedTypeReference<T> elementTypeRef) {
this.inserter = BodyInserters.fromPublisher(publisher, elementTypeRef);
return this;
}
@Override
public <T, S extends Publisher<T>> RequestHeadersSpec<?> body(S publisher, ParameterizedTypeReference<T> elementTypeRef) {
this.bodySpec.body(publisher, elementTypeRef);
public <T, P extends Publisher<T>> RequestHeadersSpec<?> body(P publisher, Class<T> elementClass) {
this.inserter = BodyInserters.fromPublisher(publisher, elementClass);
return this;
}
@Override
public RequestHeadersSpec<?> body(Object producer, Class<?> elementClass) {
this.bodySpec.body(producer, elementClass);
this.inserter = BodyInserters.fromProducer(producer, elementClass);
return this;
}
@Override
public RequestHeadersSpec<?> body(Object producer, ParameterizedTypeReference<?> elementTypeRef) {
this.bodySpec.body(producer, elementTypeRef);
this.inserter = BodyInserters.fromProducer(producer, elementTypeRef);
return this;
}
@Override
public RequestHeadersSpec<?> body(BodyInserter<?, ? super ClientHttpRequest> inserter) {
this.bodySpec.body(inserter);
this.inserter = inserter;
return this;
}
@@ -304,10 +348,57 @@ class DefaultWebTestClient implements WebTestClient {
@Override
public ResponseSpec exchange() {
ClientResponse clientResponse = this.bodySpec.exchange().block(getTimeout());
Assert.state(clientResponse != null, "No ClientResponse");
ExchangeResult result = wiretapConnector.getExchangeResult(this.requestId, this.uriTemplate, getTimeout());
return new DefaultResponseSpec(result, clientResponse, getTimeout());
ClientRequest request = (this.inserter != null ?
initRequestBuilder().body(this.inserter).build() :
initRequestBuilder().build());
ClientResponse response = exchangeFunction.exchange(request).block(getResponseTimeout());
Assert.state(response != null, "No ClientResponse");
ExchangeResult result = wiretapConnector.getExchangeResult(
this.requestId, this.uriTemplate, getResponseTimeout());
return new DefaultResponseSpec(result, response, getResponseTimeout());
}
private ClientRequest.Builder initRequestBuilder() {
ClientRequest.Builder builder = ClientRequest.create(this.httpMethod, initUri())
.headers(headers -> headers.addAll(initHeaders()))
.cookies(cookies -> cookies.addAll(initCookies()))
.attributes(attributes -> attributes.putAll(this.attributes));
if (this.httpRequestConsumer != null) {
builder.httpRequest(this.httpRequestConsumer);
}
return builder;
}
private URI initUri() {
return (this.uri != null ? this.uri : uriBuilderFactory.expand(""));
}
private HttpHeaders initHeaders() {
if (CollectionUtils.isEmpty(defaultHeaders)) {
return this.headers;
}
HttpHeaders result = new HttpHeaders();
result.putAll(defaultHeaders);
result.putAll(this.headers);
return result;
}
private MultiValueMap<String, String> initCookies() {
if (CollectionUtils.isEmpty(this.cookies)) {
return (defaultCookies != null ? defaultCookies : new LinkedMultiValueMap<>());
}
else if (CollectionUtils.isEmpty(defaultCookies)) {
return this.cookies;
}
else {
MultiValueMap<String, String> result = new LinkedMultiValueMap<>();
result.putAll(defaultCookies);
result.putAll(this.cookies);
return result;
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,20 +17,30 @@
package org.springframework.test.web.reactive.server;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.reactive.ClientHttpConnector;
import org.springframework.http.client.reactive.HttpComponentsClientHttpConnector;
import org.springframework.http.client.reactive.JettyClientHttpConnector;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.http.codec.ClientCodecConfigurer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
import org.springframework.web.reactive.function.client.ExchangeFunction;
import org.springframework.web.reactive.function.client.ExchangeFunctions;
import org.springframework.web.reactive.function.client.ExchangeStrategies;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriBuilderFactory;
/**
@@ -41,7 +51,21 @@ import org.springframework.web.util.UriBuilderFactory;
*/
class DefaultWebTestClientBuilder implements WebTestClient.Builder {
private final WebClient.Builder webClientBuilder;
private static final boolean reactorClientPresent;
private static final boolean jettyClientPresent;
private static final boolean httpComponentsClientPresent;
static {
ClassLoader loader = DefaultWebTestClientBuilder.class.getClassLoader();
reactorClientPresent = ClassUtils.isPresent("reactor.netty.http.client.HttpClient", loader);
jettyClientPresent = ClassUtils.isPresent("org.eclipse.jetty.client.HttpClient", loader);
httpComponentsClientPresent =
ClassUtils.isPresent("org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient", loader) &&
ClassUtils.isPresent("org.apache.hc.core5.reactive.ReactiveDataConsumer", loader);
}
@Nullable
private final WebHttpHandlerBuilder httpHandlerBuilder;
@@ -49,110 +73,178 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder {
@Nullable
private final ClientHttpConnector connector;
@Nullable
private String baseUrl;
@Nullable
private UriBuilderFactory uriBuilderFactory;
@Nullable
private HttpHeaders defaultHeaders;
@Nullable
private MultiValueMap<String, String> defaultCookies;
@Nullable
private List<ExchangeFilterFunction> filters;
@Nullable
private ExchangeStrategies strategies;
@Nullable
private List<Consumer<ExchangeStrategies.Builder>> strategiesConfigurers;
@Nullable
private Duration responseTimeout;
/** Connect to server via Reactor Netty. */
/** Determine connector via classpath detection. */
DefaultWebTestClientBuilder() {
this(new ReactorClientHttpConnector());
this(null, null);
}
/** Connect to server through the given connector. */
DefaultWebTestClientBuilder(ClientHttpConnector connector) {
this(null, null, connector, null);
}
/** Connect to given mock server with mock request and response. */
/** Use HttpHandlerConnector with mock server. */
DefaultWebTestClientBuilder(WebHttpHandlerBuilder httpHandlerBuilder) {
this(null, httpHandlerBuilder, null, null);
this(httpHandlerBuilder, null);
}
/** Use given connector. */
DefaultWebTestClientBuilder(ClientHttpConnector connector) {
this(null, connector);
}
DefaultWebTestClientBuilder(
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector) {
Assert.isTrue(httpHandlerBuilder == null || connector == null,
"Expected WebHttpHandlerBuilder or ClientHttpConnector but not both.");
this.connector = connector;
this.httpHandlerBuilder = (httpHandlerBuilder != null ? httpHandlerBuilder.clone() : null);
}
/** Copy constructor. */
DefaultWebTestClientBuilder(DefaultWebTestClientBuilder other) {
this(other.webClientBuilder.clone(), other.httpHandlerBuilder, other.connector,
other.responseTimeout);
}
this.httpHandlerBuilder = (other.httpHandlerBuilder != null ? other.httpHandlerBuilder.clone() : null);
this.connector = other.connector;
this.responseTimeout = other.responseTimeout;
private DefaultWebTestClientBuilder(@Nullable WebClient.Builder webClientBuilder,
@Nullable WebHttpHandlerBuilder httpHandlerBuilder, @Nullable ClientHttpConnector connector,
@Nullable Duration responseTimeout) {
Assert.isTrue(httpHandlerBuilder != null || connector != null,
"Either WebHttpHandlerBuilder or ClientHttpConnector must be provided");
this.webClientBuilder = (webClientBuilder != null ? webClientBuilder : WebClient.builder());
this.httpHandlerBuilder = (httpHandlerBuilder != null ? httpHandlerBuilder.clone() : null);
this.connector = connector;
this.responseTimeout = responseTimeout;
this.baseUrl = other.baseUrl;
this.uriBuilderFactory = other.uriBuilderFactory;
if (other.defaultHeaders != null) {
this.defaultHeaders = new HttpHeaders();
this.defaultHeaders.putAll(other.defaultHeaders);
}
else {
this.defaultHeaders = null;
}
this.defaultCookies = (other.defaultCookies != null ?
new LinkedMultiValueMap<>(other.defaultCookies) : null);
this.filters = (other.filters != null ? new ArrayList<>(other.filters) : null);
this.strategies = other.strategies;
this.strategiesConfigurers = (other.strategiesConfigurers != null ?
new ArrayList<>(other.strategiesConfigurers) : null);
}
@Override
public WebTestClient.Builder baseUrl(String baseUrl) {
this.webClientBuilder.baseUrl(baseUrl);
this.baseUrl = baseUrl;
return this;
}
@Override
public WebTestClient.Builder uriBuilderFactory(UriBuilderFactory uriBuilderFactory) {
this.webClientBuilder.uriBuilderFactory(uriBuilderFactory);
this.uriBuilderFactory = uriBuilderFactory;
return this;
}
@Override
public WebTestClient.Builder defaultHeader(String headerName, String... headerValues) {
this.webClientBuilder.defaultHeader(headerName, headerValues);
public WebTestClient.Builder defaultHeader(String header, String... values) {
initHeaders().put(header, Arrays.asList(values));
return this;
}
@Override
public WebTestClient.Builder defaultHeaders(Consumer<HttpHeaders> headersConsumer) {
this.webClientBuilder.defaultHeaders(headersConsumer);
headersConsumer.accept(initHeaders());
return this;
}
private HttpHeaders initHeaders() {
if (this.defaultHeaders == null) {
this.defaultHeaders = new HttpHeaders();
}
return this.defaultHeaders;
}
@Override
public WebTestClient.Builder defaultCookie(String cookie, String... values) {
initCookies().addAll(cookie, Arrays.asList(values));
return this;
}
@Override
public WebTestClient.Builder defaultCookie(String cookieName, String... cookieValues) {
this.webClientBuilder.defaultCookie(cookieName, cookieValues);
public WebTestClient.Builder defaultCookies(Consumer<MultiValueMap<String, String>> cookiesConsumer) {
cookiesConsumer.accept(initCookies());
return this;
}
@Override
public WebTestClient.Builder defaultCookies(
Consumer<MultiValueMap<String, String>> cookiesConsumer) {
this.webClientBuilder.defaultCookies(cookiesConsumer);
return this;
private MultiValueMap<String, String> initCookies() {
if (this.defaultCookies == null) {
this.defaultCookies = new LinkedMultiValueMap<>(3);
}
return this.defaultCookies;
}
@Override
public WebTestClient.Builder filter(ExchangeFilterFunction filter) {
this.webClientBuilder.filter(filter);
Assert.notNull(filter, "ExchangeFilterFunction must not be null");
initFilters().add(filter);
return this;
}
@Override
public WebTestClient.Builder filters(Consumer<List<ExchangeFilterFunction>> filtersConsumer) {
this.webClientBuilder.filters(filtersConsumer);
filtersConsumer.accept(initFilters());
return this;
}
private List<ExchangeFilterFunction> initFilters() {
if (this.filters == null) {
this.filters = new ArrayList<>();
}
return this.filters;
}
@Override
public WebTestClient.Builder codecs(Consumer<ClientCodecConfigurer> configurer) {
this.webClientBuilder.codecs(configurer);
if (this.strategiesConfigurers == null) {
this.strategiesConfigurers = new ArrayList<>(4);
}
this.strategiesConfigurers.add(builder -> builder.codecs(configurer));
return this;
}
@Override
public WebTestClient.Builder exchangeStrategies(ExchangeStrategies strategies) {
this.webClientBuilder.exchangeStrategies(strategies);
this.strategies = strategies;
return this;
}
@SuppressWarnings("deprecation")
@Override
@SuppressWarnings("deprecation")
public WebTestClient.Builder exchangeStrategies(Consumer<ExchangeStrategies.Builder> configurer) {
this.webClientBuilder.exchangeStrategies(configurer);
if (this.strategiesConfigurers == null) {
this.strategiesConfigurers = new ArrayList<>(4);
}
this.strategiesConfigurers.add(configurer);
return this;
}
@Override
public WebTestClient.Builder apply(WebTestClientConfigurer configurer) {
configurer.afterConfigurerAdded(this, this.httpHandlerBuilder, this.connector);
return this;
}
@@ -162,23 +254,62 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder {
return this;
}
@Override
public WebTestClient.Builder apply(WebTestClientConfigurer configurer) {
configurer.afterConfigurerAdded(this, this.httpHandlerBuilder, this.connector);
return this;
}
@Override
public WebTestClient build() {
ClientHttpConnector connectorToUse = this.connector;
if (connectorToUse == null) {
Assert.state(this.httpHandlerBuilder != null, "No WebHttpHandlerBuilder available");
connectorToUse = new HttpHandlerConnector(this.httpHandlerBuilder.build());
if (this.httpHandlerBuilder != null) {
connectorToUse = new HttpHandlerConnector(this.httpHandlerBuilder.build());
}
}
if (connectorToUse == null) {
connectorToUse = initConnector();
}
Function<ClientHttpConnector, ExchangeFunction> exchangeFactory = connector -> {
ExchangeFunction exchange = ExchangeFunctions.create(connector, initExchangeStrategies());
if (CollectionUtils.isEmpty(this.filters)) {
return exchange;
}
return this.filters.stream()
.reduce(ExchangeFilterFunction::andThen)
.map(filter -> filter.apply(exchange))
.orElse(exchange);
return new DefaultWebTestClient(this.webClientBuilder,
connectorToUse, this.responseTimeout, new DefaultWebTestClientBuilder(this));
};
return new DefaultWebTestClient(connectorToUse, exchangeFactory, initUriBuilderFactory(),
this.defaultHeaders != null ? HttpHeaders.readOnlyHttpHeaders(this.defaultHeaders) : null,
this.defaultCookies != null ? CollectionUtils.unmodifiableMultiValueMap(this.defaultCookies) : null,
this.responseTimeout, new DefaultWebTestClientBuilder(this));
}
private static ClientHttpConnector initConnector() {
if (reactorClientPresent) {
return new ReactorClientHttpConnector();
}
else if (jettyClientPresent) {
return new JettyClientHttpConnector();
}
else if (httpComponentsClientPresent) {
return new HttpComponentsClientHttpConnector();
}
throw new IllegalStateException("No suitable default ClientHttpConnector found");
}
private ExchangeStrategies initExchangeStrategies() {
if (CollectionUtils.isEmpty(this.strategiesConfigurers)) {
return (this.strategies != null ? this.strategies : ExchangeStrategies.withDefaults());
}
ExchangeStrategies.Builder builder =
(this.strategies != null ? this.strategies.mutate() : ExchangeStrategies.builder());
this.strategiesConfigurers.forEach(configurer -> configurer.accept(builder));
return builder.build();
}
private UriBuilderFactory initUriBuilderFactory() {
if (this.uriBuilderFactory != null) {
return this.uriBuilderFactory;
}
return (this.baseUrl != null ?
new DefaultUriBuilderFactory(this.baseUrl) : new DefaultUriBuilderFactory());
}
}