Browse Source
This commit introduces ClientResponse.Builder, an easier way to create a ClientResponse from an existing response, or from scratch. Issue: SPR-16553pull/1744/head
10 changed files with 879 additions and 9 deletions
@ -0,0 +1,189 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2018 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.web.reactive.function.client; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.util.function.Consumer; |
||||||
|
|
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer; |
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory; |
||||||
|
import org.springframework.core.io.buffer.DataBufferUtils; |
||||||
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory; |
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.http.ResponseCookie; |
||||||
|
import org.springframework.http.client.reactive.ClientHttpResponse; |
||||||
|
import org.springframework.lang.Nullable; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.util.CollectionUtils; |
||||||
|
import org.springframework.util.LinkedMultiValueMap; |
||||||
|
import org.springframework.util.MultiValueMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* Default implementation of {@link ClientResponse.Builder}. |
||||||
|
* |
||||||
|
* @author Arjen Poutsma |
||||||
|
* @since 5.0.5 |
||||||
|
*/ |
||||||
|
class DefaultClientResponseBuilder implements ClientResponse.Builder { |
||||||
|
|
||||||
|
private final HttpHeaders headers = new HttpHeaders(); |
||||||
|
|
||||||
|
private final MultiValueMap<String, ResponseCookie> cookies = new LinkedMultiValueMap<>(); |
||||||
|
|
||||||
|
private HttpStatus statusCode = HttpStatus.OK; |
||||||
|
|
||||||
|
private Flux<DataBuffer> body = Flux.empty(); |
||||||
|
|
||||||
|
private ExchangeStrategies strategies; |
||||||
|
|
||||||
|
|
||||||
|
public DefaultClientResponseBuilder(ExchangeStrategies strategies) { |
||||||
|
Assert.notNull(strategies, "'strategies' must not be null"); |
||||||
|
this.strategies = strategies; |
||||||
|
} |
||||||
|
|
||||||
|
public DefaultClientResponseBuilder(ClientResponse other) { |
||||||
|
this(other.strategies()); |
||||||
|
statusCode(other.statusCode()); |
||||||
|
headers(headers -> headers.addAll(other.headers().asHttpHeaders())); |
||||||
|
cookies(cookies -> cookies.addAll(other.cookies())); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public DefaultClientResponseBuilder statusCode(HttpStatus statusCode) { |
||||||
|
Assert.notNull(statusCode, "'statusCode' must not be null"); |
||||||
|
this.statusCode = statusCode; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ClientResponse.Builder header(String headerName, String... headerValues) { |
||||||
|
for (String headerValue : headerValues) { |
||||||
|
this.headers.add(headerName, headerValue); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ClientResponse.Builder headers(Consumer<HttpHeaders> headersConsumer) { |
||||||
|
Assert.notNull(headersConsumer, "'headersConsumer' must not be null"); |
||||||
|
headersConsumer.accept(this.headers); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public DefaultClientResponseBuilder cookie(String name, String... values) { |
||||||
|
for (String value : values) { |
||||||
|
this.cookies.add(name, ResponseCookie.from(name, value).build()); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ClientResponse.Builder cookies( |
||||||
|
Consumer<MultiValueMap<String, ResponseCookie>> cookiesConsumer) { |
||||||
|
Assert.notNull(cookiesConsumer, "'cookiesConsumer' must not be null"); |
||||||
|
cookiesConsumer.accept(this.cookies); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ClientResponse.Builder body(Flux<DataBuffer> body) { |
||||||
|
Assert.notNull(body, "'body' must not be null"); |
||||||
|
releaseBody(); |
||||||
|
this.body = body; |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ClientResponse.Builder body(String body) { |
||||||
|
Assert.notNull(body, "'body' must not be null"); |
||||||
|
releaseBody(); |
||||||
|
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); |
||||||
|
this.body = Flux.just(body). |
||||||
|
map(s -> { |
||||||
|
byte[] bytes = body.getBytes(StandardCharsets.UTF_8); |
||||||
|
return dataBufferFactory.wrap(bytes); |
||||||
|
}); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
private void releaseBody() { |
||||||
|
this.body.subscribe(DataBufferUtils.releaseConsumer()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ClientResponse build() { |
||||||
|
ClientHttpResponse clientHttpResponse = new BuiltClientHttpResponse(this.statusCode, |
||||||
|
this.headers, this.cookies, this.body); |
||||||
|
return new DefaultClientResponse(clientHttpResponse, this.strategies); |
||||||
|
} |
||||||
|
|
||||||
|
private static class BuiltClientHttpResponse implements ClientHttpResponse { |
||||||
|
|
||||||
|
private final HttpStatus statusCode; |
||||||
|
|
||||||
|
private final HttpHeaders headers; |
||||||
|
|
||||||
|
private final MultiValueMap<String, ResponseCookie> cookies; |
||||||
|
|
||||||
|
private final Flux<DataBuffer> body; |
||||||
|
|
||||||
|
public BuiltClientHttpResponse(HttpStatus statusCode, HttpHeaders headers, |
||||||
|
MultiValueMap<String, ResponseCookie> cookies, |
||||||
|
Flux<DataBuffer> body) { |
||||||
|
|
||||||
|
this.statusCode = statusCode; |
||||||
|
this.headers = HttpHeaders.readOnlyHttpHeaders(headers); |
||||||
|
this.cookies = unmodifiableCopy(cookies); |
||||||
|
this.body = body; |
||||||
|
} |
||||||
|
|
||||||
|
private static @Nullable <K, V> MultiValueMap<K, V> unmodifiableCopy(@Nullable MultiValueMap<K, V> original) { |
||||||
|
if (original != null) { |
||||||
|
return CollectionUtils.unmodifiableMultiValueMap(new LinkedMultiValueMap<>(original)); |
||||||
|
} |
||||||
|
else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public HttpStatus getStatusCode() { |
||||||
|
return this.statusCode; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public HttpHeaders getHeaders() { |
||||||
|
return this.headers; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public MultiValueMap<String, ResponseCookie> getCookies() { |
||||||
|
return this.cookies; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Flux<DataBuffer> getBody() { |
||||||
|
return this.body; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,176 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2018 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.web.reactive.function.client.support; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Optional; |
||||||
|
import java.util.OptionalLong; |
||||||
|
|
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
|
import org.springframework.core.ParameterizedTypeReference; |
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.http.MediaType; |
||||||
|
import org.springframework.http.ResponseCookie; |
||||||
|
import org.springframework.http.ResponseEntity; |
||||||
|
import org.springframework.http.client.reactive.ClientHttpResponse; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
import org.springframework.util.MultiValueMap; |
||||||
|
import org.springframework.web.reactive.function.BodyExtractor; |
||||||
|
import org.springframework.web.reactive.function.client.ClientResponse; |
||||||
|
import org.springframework.web.reactive.function.client.ExchangeStrategies; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implementation of the {@link ClientResponse} interface that can be subclassed |
||||||
|
* to adapt the request in a |
||||||
|
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction exchange filter function}. |
||||||
|
* All methods default to calling through to the wrapped request. |
||||||
|
* |
||||||
|
* @author Arjen Poutsma |
||||||
|
* @since 5.0.5 |
||||||
|
*/ |
||||||
|
public class ClientResponseWrapper implements ClientResponse { |
||||||
|
|
||||||
|
private final ClientResponse delegate; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new {@code ClientResponseWrapper} that wraps the given response. |
||||||
|
* @param delegate the response to wrap |
||||||
|
*/ |
||||||
|
public ClientResponseWrapper(ClientResponse delegate) { |
||||||
|
Assert.notNull(delegate, "'delegate' must not be null"); |
||||||
|
this.delegate = delegate; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Return the wrapped request. |
||||||
|
*/ |
||||||
|
public ClientResponse response() { |
||||||
|
return this.delegate; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ExchangeStrategies strategies() { |
||||||
|
return this.delegate.strategies(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public HttpStatus statusCode() { |
||||||
|
return this.delegate.statusCode(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Headers headers() { |
||||||
|
return this.delegate.headers(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public MultiValueMap<String, ResponseCookie> cookies() { |
||||||
|
return this.delegate.cookies(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> T body(BodyExtractor<T, ? super ClientHttpResponse> extractor) { |
||||||
|
return this.delegate.body(extractor); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Mono<T> bodyToMono(Class<? extends T> elementClass) { |
||||||
|
return this.delegate.bodyToMono(elementClass); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Mono<T> bodyToMono(ParameterizedTypeReference<T> typeReference) { |
||||||
|
return this.delegate.bodyToMono(typeReference); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Flux<T> bodyToFlux(Class<? extends T> elementClass) { |
||||||
|
return this.delegate.bodyToFlux(elementClass); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Flux<T> bodyToFlux(ParameterizedTypeReference<T> typeReference) { |
||||||
|
return this.delegate.bodyToFlux(typeReference); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType) { |
||||||
|
return this.delegate.toEntity(bodyType); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Mono<ResponseEntity<T>> toEntity(ParameterizedTypeReference<T> typeReference) { |
||||||
|
return this.delegate.toEntity(typeReference); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Mono<ResponseEntity<List<T>>> toEntityList(Class<T> elementType) { |
||||||
|
return this.delegate.toEntityList(elementType); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public <T> Mono<ResponseEntity<List<T>>> toEntityList(ParameterizedTypeReference<T> typeReference) { |
||||||
|
return this.delegate.toEntityList(typeReference); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Implementation of the {@code Headers} interface that can be subclassed |
||||||
|
* to adapt the headers in a |
||||||
|
* {@link org.springframework.web.reactive.function.client.ExchangeFilterFunction exchange filter function}. |
||||||
|
* All methods default to calling through to the wrapped request. |
||||||
|
*/ |
||||||
|
public static class HeadersWrapper implements ClientResponse.Headers { |
||||||
|
|
||||||
|
private final Headers headers; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new {@code HeadersWrapper} that wraps the given request. |
||||||
|
* @param headers the headers to wrap |
||||||
|
*/ |
||||||
|
public HeadersWrapper(Headers headers) { |
||||||
|
this.headers = headers; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public OptionalLong contentLength() { |
||||||
|
return this.headers.contentLength(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Optional<MediaType> contentType() { |
||||||
|
return this.headers.contentType(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<String> header(String headerName) { |
||||||
|
return this.headers.header(headerName); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public HttpHeaders asHttpHeaders() { |
||||||
|
return this.headers.asHttpHeaders(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2018 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* Classes supporting the {@code org.springframework.web.reactive.function.client} package. |
||||||
|
* Contains a {@code ClientResponse} wrapper to adapt a request. |
||||||
|
*/ |
||||||
|
@NonNullApi |
||||||
|
@NonNullFields |
||||||
|
package org.springframework.web.reactive.function.client.support; |
||||||
|
|
||||||
|
import org.springframework.lang.NonNullApi; |
||||||
|
import org.springframework.lang.NonNullFields; |
||||||
@ -0,0 +1,104 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2018 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.web.reactive.function.client; |
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
import reactor.test.StepVerifier; |
||||||
|
|
||||||
|
import org.springframework.core.io.buffer.DataBuffer; |
||||||
|
import org.springframework.core.io.buffer.DataBufferFactory; |
||||||
|
import org.springframework.core.io.buffer.DefaultDataBufferFactory; |
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.http.ResponseCookie; |
||||||
|
|
||||||
|
import static org.junit.Assert.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Arjen Poutsma |
||||||
|
*/ |
||||||
|
public class DefaultClientResponseBuilderTests { |
||||||
|
|
||||||
|
private DataBufferFactory dataBufferFactory; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void createBufferFactory() { |
||||||
|
this.dataBufferFactory = new DefaultDataBufferFactory(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void normal() { |
||||||
|
Flux<DataBuffer> body = Flux.just("baz") |
||||||
|
.map(s -> s.getBytes(StandardCharsets.UTF_8)) |
||||||
|
.map(dataBufferFactory::wrap); |
||||||
|
|
||||||
|
ClientResponse response = ClientResponse.create(HttpStatus.BAD_GATEWAY, ExchangeStrategies.withDefaults()) |
||||||
|
.header("foo", "bar") |
||||||
|
.cookie("baz", "qux") |
||||||
|
.body(body) |
||||||
|
.build(); |
||||||
|
|
||||||
|
assertEquals(HttpStatus.BAD_GATEWAY, response.statusCode()); |
||||||
|
HttpHeaders responseHeaders = response.headers().asHttpHeaders(); |
||||||
|
assertEquals("bar", responseHeaders.getFirst("foo")); |
||||||
|
assertNotNull("qux", response.cookies().getFirst("baz")); |
||||||
|
assertEquals("qux", response.cookies().getFirst("baz").getValue()); |
||||||
|
|
||||||
|
StepVerifier.create(response.bodyToFlux(String.class)) |
||||||
|
.expectNext("baz") |
||||||
|
.verifyComplete(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void from() throws Exception { |
||||||
|
Flux<DataBuffer> otherBody = Flux.just("foo", "bar") |
||||||
|
.map(s -> s.getBytes(StandardCharsets.UTF_8)) |
||||||
|
.map(dataBufferFactory::wrap); |
||||||
|
|
||||||
|
ClientResponse other = ClientResponse.create(HttpStatus.BAD_REQUEST, ExchangeStrategies.withDefaults()) |
||||||
|
.header("foo", "bar") |
||||||
|
.cookie("baz", "qux") |
||||||
|
.body(otherBody) |
||||||
|
.build(); |
||||||
|
|
||||||
|
Flux<DataBuffer> body = Flux.just("baz") |
||||||
|
.map(s -> s.getBytes(StandardCharsets.UTF_8)) |
||||||
|
.map(dataBufferFactory::wrap); |
||||||
|
|
||||||
|
ClientResponse result = ClientResponse.from(other) |
||||||
|
.headers(httpHeaders -> httpHeaders.set("foo", "baar")) |
||||||
|
.cookies(cookies -> cookies.set("baz", ResponseCookie.from("baz", "quux").build())) |
||||||
|
.body(body) |
||||||
|
.build(); |
||||||
|
|
||||||
|
assertEquals(HttpStatus.BAD_REQUEST, result.statusCode()); |
||||||
|
assertEquals(1, result.headers().asHttpHeaders().size()); |
||||||
|
assertEquals("baar", result.headers().asHttpHeaders().getFirst("foo")); |
||||||
|
assertEquals(1, result.cookies().size()); |
||||||
|
assertEquals("quux", result.cookies().getFirst("baz").getValue()); |
||||||
|
|
||||||
|
StepVerifier.create(result.bodyToFlux(String.class)) |
||||||
|
.expectNext("baz") |
||||||
|
.verifyComplete(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,163 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2018 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.web.reactive.function.client.support; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
import reactor.core.publisher.Flux; |
||||||
|
import reactor.core.publisher.Mono; |
||||||
|
|
||||||
|
import org.springframework.core.ParameterizedTypeReference; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.http.ReactiveHttpInputMessage; |
||||||
|
import org.springframework.http.ResponseCookie; |
||||||
|
import org.springframework.http.ResponseEntity; |
||||||
|
import org.springframework.util.MultiValueMap; |
||||||
|
import org.springframework.web.reactive.function.BodyExtractor; |
||||||
|
import org.springframework.web.reactive.function.BodyExtractors; |
||||||
|
import org.springframework.web.reactive.function.client.ClientResponse; |
||||||
|
|
||||||
|
import static java.util.Collections.singletonList; |
||||||
|
import static org.junit.Assert.*; |
||||||
|
import static org.mockito.Mockito.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Arjen Poutsma |
||||||
|
*/ |
||||||
|
public class ClientResponseWrapperTests { |
||||||
|
|
||||||
|
private ClientResponse mockResponse; |
||||||
|
|
||||||
|
private ClientResponseWrapper wrapper; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void createWrapper() { |
||||||
|
this.mockResponse = mock(ClientResponse.class); |
||||||
|
this.wrapper = new ClientResponseWrapper(mockResponse); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void response() throws Exception { |
||||||
|
assertSame(mockResponse, wrapper.response()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void statusCode() throws Exception { |
||||||
|
HttpStatus status = HttpStatus.BAD_REQUEST; |
||||||
|
when(mockResponse.statusCode()).thenReturn(status); |
||||||
|
|
||||||
|
assertSame(status, wrapper.statusCode()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void headers() throws Exception { |
||||||
|
ClientResponse.Headers headers = mock(ClientResponse.Headers.class); |
||||||
|
when(mockResponse.headers()).thenReturn(headers); |
||||||
|
|
||||||
|
assertSame(headers, wrapper.headers()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void cookies() throws Exception { |
||||||
|
MultiValueMap<String, ResponseCookie> cookies = mock(MultiValueMap.class); |
||||||
|
when(mockResponse.cookies()).thenReturn(cookies); |
||||||
|
|
||||||
|
assertSame(cookies, wrapper.cookies()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void bodyExtractor() throws Exception { |
||||||
|
Mono<String> result = Mono.just("foo"); |
||||||
|
BodyExtractor<Mono<String>, ReactiveHttpInputMessage> extractor = BodyExtractors.toMono(String.class); |
||||||
|
when(mockResponse.body(extractor)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.body(extractor)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void bodyToMonoClass() throws Exception { |
||||||
|
Mono<String> result = Mono.just("foo"); |
||||||
|
when(mockResponse.bodyToMono(String.class)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.bodyToMono(String.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void bodyToMonoParameterizedTypeReference() throws Exception { |
||||||
|
Mono<String> result = Mono.just("foo"); |
||||||
|
ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {}; |
||||||
|
when(mockResponse.bodyToMono(reference)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.bodyToMono(reference)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void bodyToFluxClass() throws Exception { |
||||||
|
Flux<String> result = Flux.just("foo"); |
||||||
|
when(mockResponse.bodyToFlux(String.class)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.bodyToFlux(String.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void bodyToFluxParameterizedTypeReference() throws Exception { |
||||||
|
Flux<String> result = Flux.just("foo"); |
||||||
|
ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {}; |
||||||
|
when(mockResponse.bodyToFlux(reference)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.bodyToFlux(reference)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void toEntityClass() throws Exception { |
||||||
|
Mono<ResponseEntity<String>> result = Mono.just(new ResponseEntity<>("foo", HttpStatus.OK)); |
||||||
|
when(mockResponse.toEntity(String.class)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.toEntity(String.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void toEntityParameterizedTypeReference() throws Exception { |
||||||
|
Mono<ResponseEntity<String>> result = Mono.just(new ResponseEntity<>("foo", HttpStatus.OK)); |
||||||
|
ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {}; |
||||||
|
when(mockResponse.toEntity(reference)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.toEntity(reference)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void toEntityListClass() throws Exception { |
||||||
|
Mono<ResponseEntity<List<String>>> result = Mono.just(new ResponseEntity<>(singletonList("foo"), HttpStatus.OK)); |
||||||
|
when(mockResponse.toEntityList(String.class)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.toEntityList(String.class)); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void toEntityListParameterizedTypeReference() throws Exception { |
||||||
|
Mono<ResponseEntity<List<String>>> result = Mono.just(new ResponseEntity<>(singletonList("foo"), HttpStatus.OK)); |
||||||
|
ParameterizedTypeReference<String> reference = new ParameterizedTypeReference<String>() {}; |
||||||
|
when(mockResponse.toEntityList(reference)).thenReturn(result); |
||||||
|
|
||||||
|
assertSame(result, wrapper.toEntityList(reference)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue