parent
4db0ce12e1
commit
8fc3b3bc37
|
@ -18,7 +18,6 @@ package org.springframework.test.web.reactive.server;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
@ -61,7 +60,7 @@ abstract class AbstractMockServerSpec<B extends WebTestClient.MockServerSpec<B>>
|
|||
WebHttpHandlerBuilder builder = initHttpHandlerBuilder();
|
||||
builder.filters(theFilters -> theFilters.addAll(0, this.filters));
|
||||
this.configurers.forEach(configurer -> configurer.beforeServerCreated(builder));
|
||||
return new DefaultWebTestClientBuilder(builder.build());
|
||||
return new DefaultWebTestClientBuilder(builder);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -71,15 +71,18 @@ class DefaultWebTestClient implements WebTestClient {
|
|||
|
||||
private final Duration timeout;
|
||||
|
||||
private final WebTestClient.Builder builder;
|
||||
|
||||
private final AtomicLong requestIndex = new AtomicLong();
|
||||
|
||||
|
||||
DefaultWebTestClient(WebClient.Builder clientBuilder, ClientHttpConnector connector,
|
||||
@Nullable Duration timeout) {
|
||||
@Nullable Duration timeout, WebTestClient.Builder webTestClientBuilder) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -125,8 +128,7 @@ class DefaultWebTestClient implements WebTestClient {
|
|||
|
||||
@Override
|
||||
public Builder mutate() {
|
||||
return new DefaultWebTestClientBuilder(this.wiretapConnector.getDelegate(),
|
||||
this.webClient.mutate(), this.timeout);
|
||||
return this.builder;
|
||||
}
|
||||
|
||||
private <S extends RequestHeadersSpec<?>> UriSpec<S> toUriSpec(
|
||||
|
|
|
@ -23,12 +23,13 @@ import java.util.function.Consumer;
|
|||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
|
||||
import org.springframework.http.server.reactive.HttpHandler;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
||||
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.UriBuilderFactory;
|
||||
|
||||
/**
|
||||
|
@ -41,29 +42,32 @@ class DefaultWebTestClientBuilder implements WebTestClient.Builder {
|
|||
|
||||
private final WebClient.Builder webClientBuilder;
|
||||
|
||||
private final WebHttpHandlerBuilder httpHandlerBuilder;
|
||||
|
||||
private final ClientHttpConnector connector;
|
||||
|
||||
private Duration responseTimeout;
|
||||
|
||||
|
||||
DefaultWebTestClientBuilder() {
|
||||
this(new ReactorClientHttpConnector());
|
||||
this(null, null, new ReactorClientHttpConnector(), null);
|
||||
}
|
||||
|
||||
DefaultWebTestClientBuilder(HttpHandler httpHandler) {
|
||||
this(new HttpHandlerConnector(httpHandler));
|
||||
DefaultWebTestClientBuilder(WebHttpHandlerBuilder httpHandlerBuilder) {
|
||||
this(null, httpHandlerBuilder, null, null);
|
||||
}
|
||||
|
||||
DefaultWebTestClientBuilder(ClientHttpConnector connector) {
|
||||
this(connector, null, null);
|
||||
}
|
||||
|
||||
DefaultWebTestClientBuilder(ClientHttpConnector connector,
|
||||
@Nullable WebClient.Builder webClientBuilder,
|
||||
DefaultWebTestClientBuilder(@Nullable WebClient.Builder webClientBuilder,
|
||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder,
|
||||
@Nullable ClientHttpConnector connector,
|
||||
@Nullable Duration responseTimeout) {
|
||||
|
||||
this.connector = connector;
|
||||
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.cloneBuilder() : null);
|
||||
this.connector = connector;
|
||||
this.responseTimeout = responseTimeout;
|
||||
}
|
||||
|
||||
|
@ -129,9 +133,24 @@ 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() {
|
||||
return new DefaultWebTestClient(this.webClientBuilder, this.connector, this.responseTimeout);
|
||||
|
||||
ClientHttpConnector connectorToUse = (this.connector != null ? this.connector :
|
||||
new HttpHandlerConnector(this.httpHandlerBuilder.build()));
|
||||
|
||||
DefaultWebTestClientBuilder webTestClientBuilder = new DefaultWebTestClientBuilder(
|
||||
this.webClientBuilder.build().mutate(), this.httpHandlerBuilder,
|
||||
this.connector, this.responseTimeout);
|
||||
|
||||
return new DefaultWebTestClient(this.webClientBuilder,
|
||||
connectorToUse, this.responseTimeout, webTestClientBuilder);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
|
||||
|
||||
/**
|
||||
* Apply {@code ServerWebExchange} transformations during "mock" server tests
|
||||
* with the {@code WebTestClient}.
|
||||
*
|
||||
* <p>Register the {@code WebFilter} while setting up the mock server through
|
||||
* one of the following:
|
||||
* <ul>
|
||||
* <li>{@link WebTestClient#bindToController}
|
||||
* <li>{@link WebTestClient#bindToRouterFunction}
|
||||
* <li>{@link WebTestClient#bindToApplicationContext}
|
||||
* <li>{@link WebTestClient#bindToWebHandler}
|
||||
* </ul>
|
||||
*
|
||||
* <p>Example usage:
|
||||
*
|
||||
* <pre class="code">
|
||||
* Function<ServerWebExchange, ServerWebExchange> fn1 = ...;
|
||||
* Function<ServerWebExchange, ServerWebExchange> fn2 = ...;
|
||||
*
|
||||
* ExchangeMutatorWebFilter mutator = new ExchangeMutatorWebFilter(fn1().andThen(fn2()));
|
||||
* WebTestClient client = WebTestClient.bindToController(new MyController()).webFilter(mutator).build();
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* <p>It is also possible to apply "per request" transformations:
|
||||
*
|
||||
* <pre class="code">
|
||||
* ExchangeMutatorWebFilter mutator = new ExchangeMutatorWebFilter();
|
||||
* WebTestClient client = WebTestClient.bindToController(new MyController()).webFilter(mutator).build();
|
||||
*
|
||||
* Function<ServerWebExchange, ServerWebExchange> fn1 = ...;
|
||||
* Function<ServerWebExchange, ServerWebExchange> fn2 = ...;
|
||||
*
|
||||
* client.filter(mutator.perClient(fn1().andThen(fn2()))).get().uri("/").exchange();
|
||||
* </pre>
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
*/
|
||||
public class ExchangeMutatorWebFilter implements WebFilter {
|
||||
|
||||
private final Function<ServerWebExchange, ServerWebExchange> processor;
|
||||
|
||||
private final Map<String, Function<ServerWebExchange, ServerWebExchange>> perRequestProcessors =
|
||||
new ConcurrentHashMap<>(4);
|
||||
|
||||
|
||||
public ExchangeMutatorWebFilter() {
|
||||
this(exchange -> exchange);
|
||||
}
|
||||
|
||||
public ExchangeMutatorWebFilter(Function<ServerWebExchange, ServerWebExchange> processor) {
|
||||
Assert.notNull(processor, "'processor' is required");
|
||||
this.processor = processor;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
exchange = getProcessor(exchange).apply(exchange);
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
|
||||
private Function<ServerWebExchange, ServerWebExchange> getProcessor(ServerWebExchange exchange) {
|
||||
String id = getRequestId(exchange.getRequest().getHeaders());
|
||||
Function<ServerWebExchange, ServerWebExchange> clientMutator = this.perRequestProcessors.remove(id);
|
||||
return (clientMutator != null ? this.processor.andThen(clientMutator) : this.processor);
|
||||
}
|
||||
|
||||
private String getRequestId(HttpHeaders headers) {
|
||||
String id = headers.getFirst(WebTestClient.WEBTESTCLIENT_REQUEST_ID);
|
||||
Assert.notNull(id, "No \"" + WebTestClient.WEBTESTCLIENT_REQUEST_ID + "\" header");
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the given processor only to requests performed through the client
|
||||
* instance filtered with the returned filter. See class-level Javadoc for
|
||||
* sample code.
|
||||
* @param processor the exchange processor to use
|
||||
* @return client filter for use with {@link WebTestClient#filter}
|
||||
*/
|
||||
public ExchangeFilterFunction perClient(Function<ServerWebExchange, ServerWebExchange> processor) {
|
||||
return (request, next) -> {
|
||||
String id = getRequestId(request.headers());
|
||||
this.perRequestProcessors.compute(id,
|
||||
(s, value) -> value != null ? value.andThen(processor) : processor);
|
||||
return next.exchange(request);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -38,6 +38,7 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
|||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
* @see WebTestClientConfigurer
|
||||
*/
|
||||
public interface MockServerConfigurer {
|
||||
|
||||
|
|
|
@ -193,13 +193,7 @@ public interface WebTestClient {
|
|||
/**
|
||||
* Register one or more {@link WebFilter} instances to apply to the
|
||||
* mock server.
|
||||
*
|
||||
* <p>This could be used for example to apply {@code ServerWebExchange}
|
||||
* transformations such as setting the Principal (for all requests or a
|
||||
* subset) via {@link ExchangeMutatorWebFilter}.
|
||||
*
|
||||
* @param filter one or more filters
|
||||
* @see ExchangeMutatorWebFilter
|
||||
*/
|
||||
<T extends B> T webFilter(WebFilter... filter);
|
||||
|
||||
|
@ -380,6 +374,12 @@ public interface WebTestClient {
|
|||
*/
|
||||
Builder responseTimeout(Duration timeout);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param configurer
|
||||
* @return
|
||||
*/
|
||||
Builder apply(WebTestClientConfigurer configurer);
|
||||
|
||||
/**
|
||||
* Build the {@link WebTestClient} instance.
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server;
|
||||
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
|
||||
/**
|
||||
* Contract that frameworks or applications can use to pre-package a set of
|
||||
* customizations to a {@link WebTestClient.Builder} and expose that
|
||||
* as a shortcut.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 5.0
|
||||
* @see MockServerConfigurer
|
||||
*/
|
||||
public interface WebTestClientConfigurer {
|
||||
|
||||
/**
|
||||
* Invoked once only, immediately (i.e. before this method returns).
|
||||
* @param builder the WebTestClient builder to make changes to
|
||||
* @param httpHandlerBuilder the builder for the "mock server" HttpHandler
|
||||
* this client was configured for "mock server" testing
|
||||
* @param connector the connector for "live" integration tests if this
|
||||
* server was configured for live integration testing
|
||||
*/
|
||||
void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder,
|
||||
@Nullable ClientHttpConnector connector);
|
||||
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.test.web.reactive.server.MockServerConfigurer;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.test.web.reactive.server.WebTestClientConfigurer;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
|
||||
|
||||
/**
|
||||
* Samples tests that demonstrate applying ServerWebExchange initialization.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ExchangeMutatorTests {
|
||||
|
||||
private WebTestClient webTestClient;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
this.webTestClient = WebTestClient.bindToController(new TestController())
|
||||
.apply(globalIdentity("Pablo"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useGloballyConfiguredIdentity() throws Exception {
|
||||
this.webTestClient.get().uri("/userIdentity")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("Hello Pablo!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void useLocallyConfiguredIdentity() throws Exception {
|
||||
|
||||
withIdentity(this.webTestClient, "Giovanni")
|
||||
.get().uri("/userIdentity")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("Hello Giovanni!");
|
||||
}
|
||||
|
||||
|
||||
private static MockServerConfigurer globalIdentity(String userName) {
|
||||
return new IdentityConfigurer(userName);
|
||||
}
|
||||
|
||||
private static WebTestClient withIdentity(WebTestClient client, String userName) {
|
||||
return client.mutate().apply(new IdentityConfigurer(userName)).build();
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("/userIdentity")
|
||||
public String handle(Principal principal) {
|
||||
return "Hello " + principal.getName() + "!";
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestUser implements Principal {
|
||||
|
||||
private final String name;
|
||||
|
||||
TestUser(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
private static class IdentityConfigurer implements MockServerConfigurer, WebTestClientConfigurer {
|
||||
|
||||
private final IdentityFilter filter;
|
||||
|
||||
|
||||
public IdentityConfigurer(String userName) {
|
||||
this.filter = new IdentityFilter(userName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeServerCreated(WebHttpHandlerBuilder builder) {
|
||||
builder.filters(filters -> filters.add(0, this.filter));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConfigurerAdded(WebTestClient.Builder builder,
|
||||
@Nullable WebHttpHandlerBuilder httpHandlerBuilder,
|
||||
@Nullable ClientHttpConnector connector) {
|
||||
|
||||
Assert.notNull(httpHandlerBuilder, "Not a mock server");
|
||||
httpHandlerBuilder.filters(filters -> {
|
||||
filters.removeIf(filter -> filter instanceof IdentityFilter);
|
||||
filters.add(0, this.filter);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static class IdentityFilter implements WebFilter {
|
||||
|
||||
private final Mono<Principal> userMono;
|
||||
|
||||
|
||||
IdentityFilter(String userName) {
|
||||
this.userMono = Mono.just(new TestUser(userName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
exchange = exchange.mutate().principal(this.userMono).build();
|
||||
return chain.filter(exchange);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Copyright 2002-2017 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.test.web.reactive.server.samples;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.test.web.reactive.server.ExchangeMutatorWebFilter;
|
||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Samples tests that demonstrate applying ServerWebExchange initialization.
|
||||
* @author Rossen Stoyanchev
|
||||
*/
|
||||
public class ExchangeMutatorWebFilterTests {
|
||||
|
||||
private ExchangeMutatorWebFilter exchangeMutator;
|
||||
|
||||
private WebTestClient webTestClient;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
this.exchangeMutator = new ExchangeMutatorWebFilter(userIdentity("Pablo"));
|
||||
|
||||
this.webTestClient = WebTestClient.bindToController(new TestController())
|
||||
.webFilter(this.exchangeMutator)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void globalMutator() throws Exception {
|
||||
this.webTestClient.get().uri("/userIdentity")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("Hello Pablo!");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void perRequestMutators() throws Exception {
|
||||
|
||||
this.webTestClient = WebTestClient.bindToController(new TestController())
|
||||
.webFilter(this.exchangeMutator)
|
||||
.configureClient()
|
||||
.filter(this.exchangeMutator.perClient(userIdentity("Giovanni")))
|
||||
.build();
|
||||
|
||||
this.webTestClient
|
||||
.get().uri("/userIdentity")
|
||||
.exchange()
|
||||
.expectStatus().isOk()
|
||||
.expectBody(String.class).isEqualTo("Hello Giovanni!");
|
||||
}
|
||||
|
||||
|
||||
private UnaryOperator<ServerWebExchange> userIdentity(String userName) {
|
||||
return exchange -> exchange.mutate().principal(Mono.just(new TestUser(userName))).build();
|
||||
}
|
||||
|
||||
|
||||
@RestController
|
||||
static class TestController {
|
||||
|
||||
@GetMapping("/userIdentity")
|
||||
public String handle(Principal principal) {
|
||||
return "Hello " + principal.getName() + "!";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static class TestUser implements Principal {
|
||||
|
||||
private final String name;
|
||||
|
||||
TestUser(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -96,6 +96,19 @@ public class WebHttpHandlerBuilder {
|
|||
this.webHandler = webHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
private WebHttpHandlerBuilder(WebHttpHandlerBuilder other) {
|
||||
|
||||
this.webHandler = other.webHandler;
|
||||
this.filters.addAll(other.filters);
|
||||
this.exceptionHandlers.addAll(other.exceptionHandlers);
|
||||
this.sessionManager = other.sessionManager;
|
||||
this.codecConfigurer = other.codecConfigurer;
|
||||
this.localeContextResolver = other.localeContextResolver;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Static factory method to create a new builder instance.
|
||||
|
@ -263,6 +276,14 @@ public class WebHttpHandlerBuilder {
|
|||
return adapted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone this {@link WebHttpHandlerBuilder}.
|
||||
* @return the cloned builder instance
|
||||
*/
|
||||
public WebHttpHandlerBuilder cloneBuilder() {
|
||||
return new WebHttpHandlerBuilder(this);
|
||||
}
|
||||
|
||||
|
||||
private static class SortedBeanContainer {
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.web.server.handler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -40,7 +41,7 @@ public class ExceptionHandlingWebHandler extends WebHandlerDecorator {
|
|||
|
||||
public ExceptionHandlingWebHandler(WebHandler delegate, List<WebExceptionHandler> handlers) {
|
||||
super(delegate);
|
||||
this.exceptionHandlers = Collections.unmodifiableList(handlers);
|
||||
this.exceptionHandlers = Collections.unmodifiableList(new ArrayList<>(handlers));
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue