Remove parameterisation from ClientRequest
This commit removes the parameterisation from ClientRequest, similarly to ServerResponse. Dropping the parameterisation facilitates a ClientRequest.from method that also copies the body of the target request. SPR-15234 Work in Progress
This commit is contained in:
parent
d513fe87f2
commit
45770d73ed
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.test.web.reactive.server;
|
||||
|
||||
import java.net.URI;
|
||||
|
|
@ -54,7 +55,7 @@ public class WiretapConnectorTests {
|
|||
wiretapConnector.addListener(infoRef::set);
|
||||
|
||||
ExchangeFunction exchangeFn = ExchangeFunctions.create(wiretapConnector);
|
||||
ClientRequest<Void> clientRequest = ClientRequest.method(HttpMethod.GET, URI.create("/test")).build();
|
||||
ClientRequest clientRequest = ClientRequest.method(HttpMethod.GET, URI.create("/test")).build();
|
||||
exchangeFn.exchange(clientRequest).blockMillis(0);
|
||||
|
||||
WiretapConnector.Info info = infoRef.get();
|
||||
|
|
|
|||
|
|
@ -36,12 +36,11 @@ import org.springframework.web.reactive.function.BodyInserter;
|
|||
* <p>Note that applications are more likely to perform requests through
|
||||
* {@link WebClient} rather than using this directly.
|
||||
*
|
||||
* @param <T> the type of the body that this request contains
|
||||
* @author Brian Clozel
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.0
|
||||
*/
|
||||
public interface ClientRequest<T> {
|
||||
public interface ClientRequest {
|
||||
|
||||
/**
|
||||
* Return the HTTP method.
|
||||
|
|
@ -66,7 +65,7 @@ public interface ClientRequest<T> {
|
|||
/**
|
||||
* Return the body inserter of this request.
|
||||
*/
|
||||
BodyInserter<T, ? super ClientHttpRequest> inserter();
|
||||
BodyInserter<?, ? super ClientHttpRequest> body();
|
||||
|
||||
/**
|
||||
* Writes this request to the given {@link ClientHttpRequest}.
|
||||
|
|
@ -86,11 +85,12 @@ public interface ClientRequest<T> {
|
|||
* @param other the request to copy the method, URI, headers, and cookies from
|
||||
* @return the created builder
|
||||
*/
|
||||
static Builder from(ClientRequest<?> other) {
|
||||
static Builder from(ClientRequest other) {
|
||||
Assert.notNull(other, "'other' must not be null");
|
||||
return new DefaultClientRequestBuilder(other.method(), other.url())
|
||||
.headers(other.headers())
|
||||
.cookies(other.cookies());
|
||||
.cookies(other.cookies())
|
||||
.body(other.body());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -143,28 +143,27 @@ public interface ClientRequest<T> {
|
|||
Builder cookies(MultiValueMap<String, String> cookies);
|
||||
|
||||
/**
|
||||
* Builds the request entity with no body.
|
||||
* @return the request entity
|
||||
*/
|
||||
ClientRequest<Void> build();
|
||||
|
||||
/**
|
||||
* Set the body of the request to the given {@code BodyInserter} and return it.
|
||||
* Set the body of the request to the given {@code BodyInserter}.
|
||||
* @param inserter the {@code BodyInserter} that writes to the request
|
||||
* @param <T> the type contained in the body
|
||||
* @return the built request
|
||||
* @return this builder
|
||||
*/
|
||||
<T> ClientRequest<T> body(BodyInserter<T, ? super ClientHttpRequest> inserter);
|
||||
Builder body(BodyInserter<?, ? super ClientHttpRequest> inserter);
|
||||
|
||||
/**
|
||||
* Set the body of the request to the given {@code Publisher} and return it.
|
||||
* @param publisher the {@code Publisher} to write to the request
|
||||
* @param elementClass the class of elements contained in the publisher
|
||||
* @param <T> the type of the elements contained in the publisher
|
||||
* @param <S> the type of the {@code Publisher}
|
||||
* @param <S> the type of the elements contained in the publisher
|
||||
* @param <P> the type of the {@code Publisher}
|
||||
* @return the built request
|
||||
*/
|
||||
<T, S extends Publisher<T>> ClientRequest<S> body(S publisher, Class<T> elementClass);
|
||||
<S, P extends Publisher<S>> Builder body(P publisher, Class<S> elementClass);
|
||||
|
||||
/**
|
||||
* Builds the request entity with no body.
|
||||
* @return the request entity
|
||||
*/
|
||||
ClientRequest build();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ class DefaultClientRequestBuilder implements ClientRequest.Builder {
|
|||
|
||||
private final MultiValueMap<String, String> cookies = new LinkedMultiValueMap<>();
|
||||
|
||||
private BodyInserter<?, ? super ClientHttpRequest> inserter = BodyInserters.empty();
|
||||
|
||||
|
||||
public DefaultClientRequestBuilder(HttpMethod method, URI url) {
|
||||
this.method = method;
|
||||
|
|
@ -90,23 +92,28 @@ class DefaultClientRequestBuilder implements ClientRequest.Builder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ClientRequest<Void> build() {
|
||||
return body(BodyInserters.empty());
|
||||
public <S, P extends Publisher<S>> ClientRequest.Builder body(P publisher,
|
||||
Class<S> elementClass) {
|
||||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(elementClass, "'elementClass' must not be null");
|
||||
|
||||
this.inserter = BodyInserters.fromPublisher(publisher, elementClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> ClientRequest<T> body(BodyInserter<T, ? super ClientHttpRequest> inserter) {
|
||||
Assert.notNull(inserter, "'inserter' must not be null");
|
||||
return new BodyInserterRequest<T>(this.method, this.url, this.headers, this.cookies,
|
||||
inserter);
|
||||
public ClientRequest.Builder body(BodyInserter<?, ? super ClientHttpRequest> inserter) {
|
||||
this.inserter = inserter != null ? inserter : BodyInserters.empty();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends Publisher<T>> ClientRequest<S> body(S publisher, Class<T> elementClass) {
|
||||
return body(BodyInserters.fromPublisher(publisher, elementClass));
|
||||
public ClientRequest build() {
|
||||
return new BodyInserterRequest(this.method, this.url, this.headers, this.cookies,
|
||||
this.inserter);
|
||||
}
|
||||
|
||||
private static class BodyInserterRequest<T> implements ClientRequest<T> {
|
||||
private static class BodyInserterRequest implements ClientRequest {
|
||||
|
||||
private final HttpMethod method;
|
||||
|
||||
|
|
@ -116,11 +123,11 @@ class DefaultClientRequestBuilder implements ClientRequest.Builder {
|
|||
|
||||
private final MultiValueMap<String, String> cookies;
|
||||
|
||||
private final BodyInserter<T, ? super ClientHttpRequest> inserter;
|
||||
private final BodyInserter<?, ? super ClientHttpRequest> inserter;
|
||||
|
||||
public BodyInserterRequest(HttpMethod method, URI url, HttpHeaders headers,
|
||||
MultiValueMap<String, String> cookies,
|
||||
BodyInserter<T, ? super ClientHttpRequest> inserter) {
|
||||
BodyInserter<?, ? super ClientHttpRequest> inserter) {
|
||||
this.method = method;
|
||||
this.url = url;
|
||||
this.headers = HttpHeaders.readOnlyHttpHeaders(headers);
|
||||
|
|
@ -149,7 +156,7 @@ class DefaultClientRequestBuilder implements ClientRequest.Builder {
|
|||
}
|
||||
|
||||
@Override
|
||||
public BodyInserter<T, ? super ClientHttpRequest> inserter() {
|
||||
public BodyInserter<?, ? super ClientHttpRequest> body() {
|
||||
return this.inserter;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -262,19 +262,19 @@ class DefaultWebClient implements WebClient {
|
|||
|
||||
@Override
|
||||
public Mono<ClientResponse> exchange() {
|
||||
ClientRequest<Void> request = initRequestBuilder().build();
|
||||
ClientRequest request = this.initRequestBuilder().build();
|
||||
return getExchangeFunction().exchange(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Mono<ClientResponse> exchange(BodyInserter<T, ? super ClientHttpRequest> inserter) {
|
||||
ClientRequest<T> request = initRequestBuilder().body(inserter);
|
||||
ClientRequest request = this.initRequestBuilder().body(inserter).build();
|
||||
return getExchangeFunction().exchange(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends Publisher<T>> Mono<ClientResponse> exchange(S publisher, Class<T> elementClass) {
|
||||
ClientRequest<S> request = initRequestBuilder().headers(this.headers).body(publisher, elementClass);
|
||||
ClientRequest request = initRequestBuilder().headers(this.headers).body(publisher, elementClass).build();
|
||||
return getExchangeFunction().exchange(request);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -41,7 +41,7 @@ public interface ExchangeFilterFunction {
|
|||
* @param next the next exchange function in the chain
|
||||
* @return the filtered response
|
||||
*/
|
||||
Mono<ClientResponse> filter(ClientRequest<?> request, ExchangeFunction next);
|
||||
Mono<ClientResponse> filter(ClientRequest request, ExchangeFunction next);
|
||||
|
||||
/**
|
||||
* Return a composed filter function that first applies this filter, and then applies the
|
||||
|
|
@ -74,8 +74,8 @@ public interface ExchangeFilterFunction {
|
|||
* @param requestProcessor the request processor
|
||||
* @return the filter adaptation of the request processor
|
||||
*/
|
||||
static ExchangeFilterFunction ofRequestProcessor(Function<ClientRequest<?>,
|
||||
Mono<ClientRequest<?>>> requestProcessor) {
|
||||
static ExchangeFilterFunction ofRequestProcessor(Function<ClientRequest,
|
||||
Mono<ClientRequest>> requestProcessor) {
|
||||
|
||||
Assert.notNull(requestProcessor, "'requestProcessor' must not be null");
|
||||
return (request, next) -> requestProcessor.apply(request).then(next::exchange);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -47,9 +47,9 @@ public abstract class ExchangeFilterFunctions {
|
|||
return ExchangeFilterFunction.ofRequestProcessor(
|
||||
clientRequest -> {
|
||||
String authorization = authorization(username, password);
|
||||
ClientRequest<?> authorizedRequest = ClientRequest.from(clientRequest)
|
||||
ClientRequest authorizedRequest = ClientRequest.from(clientRequest)
|
||||
.header(HttpHeaders.AUTHORIZATION, authorization)
|
||||
.body(clientRequest.inserter());
|
||||
.build();
|
||||
return Mono.just(authorizedRequest);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public interface ExchangeFunction {
|
|||
* @param request the request to exchange
|
||||
* @return the delayed response
|
||||
*/
|
||||
Mono<ClientResponse> exchange(ClientRequest<?> request);
|
||||
Mono<ClientResponse> exchange(ClientRequest request);
|
||||
|
||||
/**
|
||||
* Filters this exchange function with the given {@code ExchangeFilterFunction}, resulting in a
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ public abstract class ExchangeFunctions {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Mono<ClientResponse> exchange(ClientRequest<?> request) {
|
||||
public Mono<ClientResponse> exchange(ClientRequest request) {
|
||||
Assert.notNull(request, "'request' must not be null");
|
||||
|
||||
return this.connector
|
||||
|
|
|
|||
|
|
@ -37,7 +37,6 @@ import org.springframework.web.reactive.function.BodyInserter;
|
|||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.http.HttpMethod.DELETE;
|
||||
|
|
@ -51,10 +50,10 @@ public class DefaultClientRequestBuilderTests {
|
|||
|
||||
@Test
|
||||
public void from() throws Exception {
|
||||
ClientRequest<Void> other = ClientRequest.method(GET, URI.create("http://example.com"))
|
||||
ClientRequest other = ClientRequest.method(GET, URI.create("http://example.com"))
|
||||
.header("foo", "bar")
|
||||
.cookie("baz", "qux").build();
|
||||
ClientRequest<Void> result = ClientRequest.from(other).build();
|
||||
ClientRequest result = ClientRequest.from(other).build();
|
||||
assertEquals(new URI("http://example.com"), result.url());
|
||||
assertEquals(GET, result.method());
|
||||
assertEquals("bar", result.headers().getFirst("foo"));
|
||||
|
|
@ -64,21 +63,21 @@ public class DefaultClientRequestBuilderTests {
|
|||
@Test
|
||||
public void method() throws Exception {
|
||||
URI url = new URI("http://example.com");
|
||||
ClientRequest<Void> result = ClientRequest.method(DELETE, url).build();
|
||||
ClientRequest result = ClientRequest.method(DELETE, url).build();
|
||||
assertEquals(url, result.url());
|
||||
assertEquals(DELETE, result.method());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cookie() throws Exception {
|
||||
ClientRequest<Void> result = ClientRequest.method(GET, URI.create("http://example.com"))
|
||||
ClientRequest result = ClientRequest.method(GET, URI.create("http://example.com"))
|
||||
.cookie("foo", "bar").build();
|
||||
assertEquals("bar", result.cookies().getFirst("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void build() throws Exception {
|
||||
ClientRequest<Void> result = ClientRequest.method(GET, URI.create("http://example.com"))
|
||||
ClientRequest result = ClientRequest.method(GET, URI.create("http://example.com"))
|
||||
.header("MyKey", "MyValue")
|
||||
.cookie("foo", "bar")
|
||||
.build();
|
||||
|
|
@ -105,8 +104,8 @@ public class DefaultClientRequestBuilderTests {
|
|||
return response.writeWith(Mono.just(buffer));
|
||||
};
|
||||
|
||||
ClientRequest<String> result = ClientRequest.method(POST, URI.create("http://example.com"))
|
||||
.body(inserter);
|
||||
ClientRequest result = ClientRequest.method(POST, URI.create("http://example.com"))
|
||||
.body(inserter).build();
|
||||
|
||||
List<HttpMessageWriter<?>> messageWriters = new ArrayList<>();
|
||||
messageWriters.add(new EncoderHttpMessageWriter<>(new CharSequenceEncoder()));
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.reactive.function.client;
|
||||
|
||||
import java.util.Collections;
|
||||
|
|
@ -42,7 +43,7 @@ public class DefaultWebClientTests {
|
|||
private ExchangeFunction exchangeFunction;
|
||||
|
||||
@Captor
|
||||
private ArgumentCaptor<ClientRequest<?>> captor;
|
||||
private ArgumentCaptor<ClientRequest> captor;
|
||||
|
||||
|
||||
@Before
|
||||
|
|
@ -58,7 +59,7 @@ public class DefaultWebClientTests {
|
|||
WebClient client = builder().build();
|
||||
client.get().uri("/path").exchange();
|
||||
|
||||
ClientRequest<?> request = verifyExchange();
|
||||
ClientRequest request = verifyExchange();
|
||||
assertEquals("/base/path", request.url().toString());
|
||||
assertEquals(new HttpHeaders(), request.headers());
|
||||
assertEquals(Collections.emptyMap(), request.cookies());
|
||||
|
|
@ -69,7 +70,7 @@ public class DefaultWebClientTests {
|
|||
WebClient client = builder().build();
|
||||
client.get().uri(builder -> builder.path("/path").queryParam("q", "12").build()).exchange();
|
||||
|
||||
ClientRequest<?> request = verifyExchange();
|
||||
ClientRequest request = verifyExchange();
|
||||
assertEquals("/base/path?q=12", request.url().toString());
|
||||
verifyNoMoreInteractions(this.exchangeFunction);
|
||||
}
|
||||
|
|
@ -79,7 +80,7 @@ public class DefaultWebClientTests {
|
|||
WebClient client = builder().build();
|
||||
client.get().uri(builder -> builder.replacePath("/path").build()).exchange();
|
||||
|
||||
ClientRequest<?> request = verifyExchange();
|
||||
ClientRequest request = verifyExchange();
|
||||
assertEquals("/path", request.url().toString());
|
||||
verifyNoMoreInteractions(this.exchangeFunction);
|
||||
}
|
||||
|
|
@ -89,7 +90,7 @@ public class DefaultWebClientTests {
|
|||
WebClient client = builder().build();
|
||||
client.get().uri("/path").accept(MediaType.APPLICATION_JSON).cookie("id", "123").exchange();
|
||||
|
||||
ClientRequest<?> request = verifyExchange();
|
||||
ClientRequest request = verifyExchange();
|
||||
assertEquals("application/json", request.headers().getFirst("Accept"));
|
||||
assertEquals("123", request.cookies().getFirst("id"));
|
||||
verifyNoMoreInteractions(this.exchangeFunction);
|
||||
|
|
@ -100,7 +101,7 @@ public class DefaultWebClientTests {
|
|||
WebClient client = builder().defaultHeader("Accept", "application/json").defaultCookie("id", "123").build();
|
||||
client.get().uri("/path").exchange();
|
||||
|
||||
ClientRequest<?> request = verifyExchange();
|
||||
ClientRequest request = verifyExchange();
|
||||
assertEquals("application/json", request.headers().getFirst("Accept"));
|
||||
assertEquals("123", request.cookies().getFirst("id"));
|
||||
verifyNoMoreInteractions(this.exchangeFunction);
|
||||
|
|
@ -111,7 +112,7 @@ public class DefaultWebClientTests {
|
|||
WebClient client = builder().defaultHeader("Accept", "application/json").defaultCookie("id", "123").build();
|
||||
client.get().uri("/path").header("Accept", "application/xml").cookie("id", "456").exchange();
|
||||
|
||||
ClientRequest<?> request = verifyExchange();
|
||||
ClientRequest request = verifyExchange();
|
||||
assertEquals("application/xml", request.headers().getFirst("Accept"));
|
||||
assertEquals("456", request.cookies().getFirst("id"));
|
||||
verifyNoMoreInteractions(this.exchangeFunction);
|
||||
|
|
@ -122,8 +123,8 @@ public class DefaultWebClientTests {
|
|||
return WebClient.builder().baseUrl("/base").exchangeFunction(this.exchangeFunction);
|
||||
}
|
||||
|
||||
private ClientRequest<?> verifyExchange() {
|
||||
ClientRequest<?> request = this.captor.getValue();
|
||||
private ClientRequest verifyExchange() {
|
||||
ClientRequest request = this.captor.getValue();
|
||||
Mockito.verify(this.exchangeFunction).exchange(request);
|
||||
verifyNoMoreInteractions(this.exchangeFunction);
|
||||
return request;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -22,7 +22,6 @@ import org.junit.Test;
|
|||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
|
@ -37,7 +36,7 @@ public class ExchangeFilterFunctionsTests {
|
|||
|
||||
@Test
|
||||
public void andThen() throws Exception {
|
||||
ClientRequest<Void> request = ClientRequest.method(GET, URI.create("http://example.com")).build();
|
||||
ClientRequest request = ClientRequest.method(GET, URI.create("http://example.com")).build();
|
||||
ClientResponse response = mock(ClientResponse.class);
|
||||
ExchangeFunction exchange = r -> Mono.just(response);
|
||||
|
||||
|
|
@ -67,7 +66,7 @@ public class ExchangeFilterFunctionsTests {
|
|||
|
||||
@Test
|
||||
public void apply() throws Exception {
|
||||
ClientRequest<Void> request = ClientRequest.method(GET, URI.create("http://example.com")).build();
|
||||
ClientRequest request = ClientRequest.method(GET, URI.create("http://example.com")).build();
|
||||
ClientResponse response = mock(ClientResponse.class);
|
||||
ExchangeFunction exchange = r -> Mono.just(response);
|
||||
|
||||
|
|
@ -86,7 +85,7 @@ public class ExchangeFilterFunctionsTests {
|
|||
|
||||
@Test
|
||||
public void basicAuthentication() throws Exception {
|
||||
ClientRequest<Void> request = ClientRequest.method(GET, URI.create("http://example.com")).build();
|
||||
ClientRequest request = ClientRequest.method(GET, URI.create("http://example.com")).build();
|
||||
ClientResponse response = mock(ClientResponse.class);
|
||||
|
||||
ExchangeFunction exchange = r -> {
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ public class WebClientIntegrationTests {
|
|||
|
||||
WebClient filteredClient = this.webClient.filter(
|
||||
(request, next) -> {
|
||||
ClientRequest<?> filteredRequest = ClientRequest.from(request).header("foo", "bar").build();
|
||||
ClientRequest filteredRequest = ClientRequest.from(request).header("foo", "bar").build();
|
||||
return next.exchange(filteredRequest);
|
||||
});
|
||||
|
||||
|
|
@ -278,7 +278,7 @@ public class WebClientIntegrationTests {
|
|||
|
||||
WebClient filteredClient = this.webClient.filter(
|
||||
(request, next) -> {
|
||||
ClientRequest<?> filteredRequest = ClientRequest.from(request).header("foo", "bar").build();
|
||||
ClientRequest filteredRequest = ClientRequest.from(request).header("foo", "bar").build();
|
||||
return next.exchange(filteredRequest);
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue