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:
Arjen Poutsma
2017-02-10 11:46:38 +01:00
parent d513fe87f2
commit 45770d73ed
12 changed files with 73 additions and 67 deletions

View File

@@ -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();
}

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
});
}

View File

@@ -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

View File

@@ -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