diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/HttpMessageExtractor.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractor.java similarity index 60% rename from spring-web-reactive/src/main/java/org/springframework/web/reactive/function/HttpMessageExtractor.java rename to spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractor.java index ddaa90a069..c42d92a563 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/HttpMessageExtractor.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractor.java @@ -16,24 +16,26 @@ package org.springframework.web.reactive.function; -import org.springframework.http.ReactiveHttpInputMessage; +import org.springframework.http.server.reactive.ServerHttpRequest; /** - * Contract to extract the content of a raw {@link ReactiveHttpInputMessage} decoding - * the request body and using a target composition API. + * A function that can extract data from a {@link Request} body. * - * @author Brian Clozel + * @param the type of data to extract * @author Arjen Poutsma * @since 5.0 + * @see Request#body(BodyExtractor) + * @see BodyExtractors */ @FunctionalInterface -public interface HttpMessageExtractor { +public interface BodyExtractor { /** - * Extract content from the response body - * @param message the raw HTTP message - * @return the extracted content + * Extract from the given request. + * @param request the request to extract from + * @param configuration the configuration to use + * @return the extracted data */ - T extract(R message); + T extract(ServerHttpRequest request, Configuration configuration); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java new file mode 100644 index 0000000000..1c2ebfec16 --- /dev/null +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyExtractors.java @@ -0,0 +1,130 @@ +/* + * Copyright 2002-2016 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; + +import java.util.Collections; +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.core.ResolvableType; +import org.springframework.http.MediaType; +import org.springframework.http.codec.HttpMessageReader; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.util.Assert; +import org.springframework.web.server.UnsupportedMediaTypeStatusException; + +/** + * Implementations of {@link BodyExtractor} that read various bodies, such a reactive streams. + * + * @author Arjen Poutsma + * @since 5.0 + */ +public abstract class BodyExtractors { + + /** + * Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}. + * @param elementClass the class of element in the {@code Mono} + * @param the element type + * @return a {@code BodyExtractor} that reads a mono + */ + public static BodyExtractor> toMono(Class elementClass) { + Assert.notNull(elementClass, "'elementClass' must not be null"); + return toMono(ResolvableType.forClass(elementClass)); + } + + /** + * Return a {@code BodyExtractor} that reads into a Reactor {@link Mono}. + * @param elementType the type of element in the {@code Mono} + * @param the element type + * @return a {@code BodyExtractor} that reads a mono + */ + public static BodyExtractor> toMono(ResolvableType elementType) { + Assert.notNull(elementType, "'elementType' must not be null"); + return (request, configuration) -> readWithMessageReaders(request, configuration, + elementType, + reader -> reader.readMono(elementType, request, Collections.emptyMap()), + Mono::error); + } + + /** + * Return a {@code BodyExtractor} that reads into a Reactor {@link Flux}. + * @param elementClass the class of element in the {@code Flux} + * @param the element type + * @return a {@code BodyExtractor} that reads a mono + */ + public static BodyExtractor> toFlux(Class elementClass) { + Assert.notNull(elementClass, "'elementClass' must not be null"); + return toFlux(ResolvableType.forClass(elementClass)); + } + + /** + * Return a {@code BodyExtractor} that reads into a Reactor {@link Flux}. + * @param elementType the type of element in the {@code Flux} + * @param the element type + * @return a {@code BodyExtractor} that reads a mono + */ + public static BodyExtractor> toFlux(ResolvableType elementType) { + Assert.notNull(elementType, "'elementType' must not be null"); + return (request, configuration) -> readWithMessageReaders(request, configuration, + elementType, + reader -> reader.read(elementType, request, Collections.emptyMap()), + Flux::error); + } + + private static > S readWithMessageReaders( + ServerHttpRequest request, + Configuration configuration, + ResolvableType elementType, + Function, S> readerFunction, + Function unsupportedError) { + + MediaType contentType = contentType(request); + Supplier>> messageReaders = + configuration.messageReaders(); + return messageReaders.get() + .filter(r -> r.canRead(elementType, contentType, Collections.emptyMap())) + .findFirst() + .map(BodyExtractors::cast) + .map(readerFunction) + .orElseGet(() -> { + List supportedMediaTypes = messageReaders.get() + .flatMap(reader -> reader.getReadableMediaTypes().stream()) + .collect(Collectors.toList()); + UnsupportedMediaTypeStatusException error = + new UnsupportedMediaTypeStatusException(contentType, supportedMediaTypes); + return unsupportedError.apply(error); + }); + } + + private static MediaType contentType(ServerHttpRequest request) { + MediaType result = request.getHeaders().getContentType(); + return result != null ? result : MediaType.APPLICATION_OCTET_STREAM; + } + + @SuppressWarnings("unchecked") + private static HttpMessageReader cast(HttpMessageReader messageReader) { + return (HttpMessageReader) messageReader; + } + +} diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulator.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulator.java index c81ab4cfc3..66636f83e9 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulator.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulator.java @@ -25,10 +25,11 @@ import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.util.Assert; /** - * A combination of functions that can populate {@link Response#body()}. + * A combination of functions that can populate a {@link Response} body. * * @author Arjen Poutsma * @since 5.0 + * @see Response#body() * @see Response.BodyBuilder#body(BodyPopulator) * @see BodyPopulators */ diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulators.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulators.java index 402eec35e4..273ccdfdca 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulators.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/BodyPopulators.java @@ -61,7 +61,7 @@ public abstract class BodyPopulators { * @param body the body of the response * @return a {@code BodyPopulator} that writes a single object */ - public static BodyPopulator ofObject(T body) { + public static BodyPopulator fromObject(T body) { Assert.notNull(body, "'body' must not be null"); return BodyPopulator.of( (response, configuration) -> writeWithMessageWriters(response, configuration, @@ -77,12 +77,12 @@ public abstract class BodyPopulators { * @param the type of the {@code Publisher}. * @return a {@code BodyPopulator} that writes a {@code Publisher} */ - public static , T> BodyPopulator ofPublisher(S publisher, + public static , T> BodyPopulator fromPublisher(S publisher, Class elementClass) { Assert.notNull(publisher, "'publisher' must not be null"); Assert.notNull(elementClass, "'elementClass' must not be null"); - return ofPublisher(publisher, ResolvableType.forClass(elementClass)); + return fromPublisher(publisher, ResolvableType.forClass(elementClass)); } /** @@ -93,7 +93,7 @@ public abstract class BodyPopulators { * @param the type of the {@code Publisher}. * @return a {@code BodyPopulator} that writes a {@code Publisher} */ - public static , T> BodyPopulator ofPublisher(S publisher, + public static , T> BodyPopulator fromPublisher(S publisher, ResolvableType elementType) { Assert.notNull(publisher, "'publisher' must not be null"); @@ -114,7 +114,7 @@ public abstract class BodyPopulators { * @param the type of the {@code Resource} * @return a {@code BodyPopulator} that writes a {@code Publisher} */ - public static BodyPopulator ofResource(T resource) { + public static BodyPopulator fromResource(T resource) { Assert.notNull(resource, "'resource' must not be null"); return BodyPopulator.of( (response, configuration) -> { @@ -134,7 +134,7 @@ public abstract class BodyPopulators { * @return a {@code BodyPopulator} that writes a {@code ServerSentEvent} publisher * @see Server-Sent Events W3C recommendation */ - public static >> BodyPopulator ofServerSentEvents( + public static >> BodyPopulator fromServerSentEvents( S eventsPublisher) { Assert.notNull(eventsPublisher, "'eventsPublisher' must not be null"); @@ -159,12 +159,12 @@ public abstract class BodyPopulators { * Server-Sent Events * @see Server-Sent Events W3C recommendation */ - public static > BodyPopulator ofServerSentEvents(S eventsPublisher, + public static > BodyPopulator fromServerSentEvents(S eventsPublisher, Class eventClass) { Assert.notNull(eventsPublisher, "'eventsPublisher' must not be null"); Assert.notNull(eventClass, "'eventClass' must not be null"); - return ofServerSentEvents(eventsPublisher, ResolvableType.forClass(eventClass)); + return fromServerSentEvents(eventsPublisher, ResolvableType.forClass(eventClass)); } /** @@ -177,7 +177,7 @@ public abstract class BodyPopulators { * Server-Sent Events * @see Server-Sent Events W3C recommendation */ - public static > BodyPopulator ofServerSentEvents(S eventsPublisher, + public static > BodyPopulator fromServerSentEvents(S eventsPublisher, ResolvableType eventType) { Assert.notNull(eventsPublisher, "'eventsPublisher' must not be null"); @@ -222,7 +222,7 @@ public abstract class BodyPopulators { } @SuppressWarnings("unchecked") - public static HttpMessageWriter cast(HttpMessageWriter messageWriter) { + private static HttpMessageWriter cast(HttpMessageWriter messageWriter) { return (HttpMessageWriter) messageWriter; } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/CastingUtils.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/CastingUtils.java index 3cb3bd36b4..5aba8f8286 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/CastingUtils.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/CastingUtils.java @@ -16,17 +16,12 @@ package org.springframework.web.reactive.function; -import org.springframework.http.codec.HttpMessageReader; - /** * @author Arjen Poutsma */ @SuppressWarnings("unchecked") abstract class CastingUtils { - public static HttpMessageReader cast(HttpMessageReader messageReader) { - return (HttpMessageReader) messageReader; - } public static HandlerFunction cast(HandlerFunction handlerFunction) { return (HandlerFunction) handlerFunction; diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Configuration.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Configuration.java index 7f49258a28..3bfd383f10 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Configuration.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Configuration.java @@ -40,7 +40,7 @@ public interface Configuration { * Return a mutable, empty builder for a {@code Configuration}. * @return the builder */ - static Builder builder() { + static Builder empty() { return new DefaultConfigurationBuilder(); } @@ -48,7 +48,7 @@ public interface Configuration { * Return a mutable builder for a {@code Configuration} with a default initialization. * @return the builder */ - static Builder defaultBuilder() { + static Builder builder() { DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(); builder.defaultConfiguration(); return builder; diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java index 0eba31be33..64329282b1 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/DefaultRequest.java @@ -24,25 +24,13 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.OptionalLong; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.reactivestreams.Publisher; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import org.springframework.core.ResolvableType; -import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; import org.springframework.http.MediaType; -import org.springframework.http.codec.HttpMessageReader; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.server.ServerWebExchange; -import org.springframework.web.server.UnsupportedMediaTypeStatusException; /** * {@code Request} implementation based on a {@link ServerWebExchange}. @@ -54,12 +42,12 @@ class DefaultRequest implements Request { private final Headers headers; - private final Body body; + private final Configuration configuration; - DefaultRequest(ServerWebExchange exchange) { + DefaultRequest(ServerWebExchange exchange, Configuration configuration) { this.exchange = exchange; + this.configuration = configuration; this.headers = new DefaultHeaders(); - this.body = new DefaultBody(); } @Override @@ -78,8 +66,8 @@ class DefaultRequest implements Request { } @Override - public Body body() { - return this.body; + public T body(BodyExtractor extractor) { + return extractor.extract(request(), this.configuration); } @Override @@ -163,56 +151,4 @@ class DefaultRequest implements Request { } - private class DefaultBody implements Body { - - @Override - public Flux stream() { - return request().getBody(); - } - - @Override - public Flux convertTo(Class aClass) { - ResolvableType elementType = ResolvableType.forClass(aClass); - return convertTo(aClass, reader -> reader.read(elementType, request(), Collections.emptyMap())); - } - - @Override - public Mono convertToMono(Class aClass) { - ResolvableType elementType = ResolvableType.forClass(aClass); - return convertTo(aClass, reader -> reader.readMono(elementType, request(), Collections.emptyMap())); - } - - private > S convertTo(Class targetClass, - Function, S> readerFunction) { - ResolvableType elementType = ResolvableType.forClass(targetClass); - MediaType contentType = headers.contentType().orElse(MediaType.APPLICATION_OCTET_STREAM); - Supplier>> messageReaderStream = configuration(exchange).messageReaders(); - return messageReaderStream.get() - .filter(r -> r.canRead(elementType, contentType, Collections.emptyMap())) - .findFirst() - .map(CastingUtils::cast) - .map(readerFunction) - .orElseGet(() -> { - List supportedMediaTypes = messageReaderStream.get() - .flatMap(messageReader -> messageReader.getReadableMediaTypes().stream()) - .collect(Collectors.toList()); - return cast( - Mono.error(new UnsupportedMediaTypeStatusException(contentType, supportedMediaTypes))); - }); - } - - private Configuration configuration(ServerWebExchange exchange) { - return exchange.getAttribute( - RoutingFunctions.CONFIGURATION_ATTRIBUTE) - .orElseThrow(() -> new IllegalStateException( - "Could not find Configuration in ServerWebExchange")); - } - - @SuppressWarnings("unchecked") - private > S cast(Mono mono) { - return (S) mono; - } - - } - } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Request.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Request.java index 10e5e1d0d6..13dcb37838 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Request.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/Request.java @@ -24,19 +24,15 @@ import java.util.Map; import java.util.Optional; import java.util.OptionalLong; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; import org.springframework.http.MediaType; -import org.springframework.web.client.reactive.BodyExtractor; /** - * Represents an HTTP request, as handled by a {@linkplain HandlerFunction handler function}. - * Access to headers and body is offered by {@link Headers} and {@link Body} respectively. + * Represents an HTTP request, as handled by a {@code HandlerFunction}. + * Access to headers and body is offered by {@link Headers} and + * {@link #body(BodyExtractor)} respectively. * * @author Arjen Poutsma * @since 5.0 @@ -66,10 +62,12 @@ public interface Request { Headers headers(); /** - * Return the body of this request. + * Extract the body with the given {@code BodyExtractor}. + * @param extractor the {@code BodyExtractor} that reads from the request + * @param the type of the body returned + * @return the extracted body */ - Body body(); -// T body(BodyExtractor extractor); + T body(BodyExtractor extractor); /** * Return the request attribute value if present. @@ -171,33 +169,4 @@ public interface Request { } - /** - * Represents the body of the HTTP request. - * @see Request#body() - */ - interface Body { - - /** - * Return the request body as a stream of {@linkplain DataBuffer data buffers}. - * @return the request body byte stream - */ - Flux stream(); - - /** - * Converts the body into a multiple-element stream of the given type. - * @param aClass the type - * @param the type of the element contained in the flux - * @return a flux that streams element of the given type - */ - Flux convertTo(Class aClass); - - /** - * Converts the body into a single-element stream of the given type. - * @param aClass the type - * @param the type of the element contained in the mono - * @return a flux that streams element of the given type - */ - Mono convertToMono(Class aClass); - - } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RoutingFunctions.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RoutingFunctions.java index 78f3720d3a..24860ac254 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RoutingFunctions.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RoutingFunctions.java @@ -112,7 +112,7 @@ public abstract class RoutingFunctions { /** * Converts the given {@linkplain RoutingFunction routing function} into a {@link HttpHandler}. - * This conversion uses the {@linkplain Configuration#defaultBuilder() default configuration}. + * This conversion uses the {@linkplain Configuration#builder() default configuration}. * *

The returned {@code HttpHandler} can be adapted to run in * {@linkplain org.springframework.http.server.reactive.ServletHttpHandlerAdapter Servlet 3.1+}, @@ -146,8 +146,8 @@ public abstract class RoutingFunctions { Assert.notNull(configuration, "'configuration' must not be null"); return new HttpWebHandlerAdapter(exchange -> { - Request request = new DefaultRequest(exchange); - addAttributes(exchange, request, configuration); + Request request = new DefaultRequest(exchange, configuration); + addAttributes(exchange, request); HandlerFunction handlerFunction = routingFunction.route(request).orElse(notFound()); Response response = handlerFunction.handle(request); @@ -157,7 +157,7 @@ public abstract class RoutingFunctions { /** * Converts the given {@linkplain RoutingFunction routing function} into a {@link HandlerMapping}. - * This conversion uses the {@linkplain Configuration#defaultBuilder() default configuration}. + * This conversion uses the {@linkplain Configuration#builder() default configuration}. * *

The returned {@code HttpHandler} can be run in a * {@link org.springframework.web.reactive.DispatcherHandler}. @@ -188,8 +188,8 @@ public abstract class RoutingFunctions { Assert.notNull(configuration, "'configuration' must not be null"); return exchange -> { - Request request = new DefaultRequest(exchange); - addAttributes(exchange, request, configuration); + Request request = new DefaultRequest(exchange, configuration); + addAttributes(exchange, request); Optional> route = routingFunction.route(request); return Mono.justOrEmpty(route); @@ -197,14 +197,12 @@ public abstract class RoutingFunctions { } private static Configuration defaultConfiguration() { - return Configuration.defaultBuilder().build(); + return Configuration.builder().build(); } - private static void addAttributes(ServerWebExchange exchange, Request request, - Configuration configuration) { + private static void addAttributes(ServerWebExchange exchange, Request request) { Map attributes = exchange.getAttributes(); attributes.put(REQUEST_ATTRIBUTE, request); - attributes.put(CONFIGURATION_ATTRIBUTE, configuration); } @SuppressWarnings("unchecked") diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/RequestWrapper.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/RequestWrapper.java index 5c9439b30d..4d1d998e90 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/RequestWrapper.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/RequestWrapper.java @@ -24,15 +24,12 @@ import java.util.Map; import java.util.Optional; import java.util.OptionalLong; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; import org.springframework.http.MediaType; import org.springframework.util.Assert; +import org.springframework.web.reactive.function.BodyExtractor; import org.springframework.web.reactive.function.HandlerFunction; import org.springframework.web.reactive.function.Request; @@ -86,8 +83,8 @@ public class RequestWrapper implements Request { } @Override - public Body body() { - return this.request.body(); + public T body(BodyExtractor extractor) { + return this.request.body(extractor); } @Override @@ -174,38 +171,4 @@ public class RequestWrapper implements Request { } } - /** - * Implementation of the {@link Body} interface that can be subclassed to adapt the headers to a - * {@link HandlerFunction handler function}. All methods default to calling through to the wrapped body. - */ - public static class BodyWrapper implements Request.Body { - - private final Body body; - - /** - * Create a new {@code DelegatingBody} that wraps the given body. - * - * @param body the body to wrap - */ - public BodyWrapper(Body body) { - Assert.notNull(body, "'body' must not be null"); - this.body = body; - } - - @Override - public Flux stream() { - return this.body.stream(); - } - - @Override - public Flux convertTo(Class aClass) { - return this.body.convertTo(aClass); - } - - @Override - public Mono convertToMono(Class aClass) { - return this.body.convertToMono(aClass); - } - - } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ResponseResultHandler.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ResponseResultHandler.java index a5f90afa79..25a19ad1d3 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ResponseResultHandler.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ResponseResultHandler.java @@ -36,7 +36,7 @@ public class ResponseResultHandler implements HandlerResultHandler { private final Configuration configuration; public ResponseResultHandler() { - this(Configuration.defaultBuilder().build()); + this(Configuration.builder().build()); } public ResponseResultHandler(Configuration configuration) { diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java new file mode 100644 index 0000000000..10ef93ef6f --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyExtractorsTests.java @@ -0,0 +1,101 @@ +/* + * Copyright 2002-2016 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; + +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DefaultDataBuffer; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.MediaType; +import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest; +import org.springframework.tests.TestSubscriber; +import org.springframework.web.server.UnsupportedMediaTypeStatusException; + +/** + * @author Arjen Poutsma + */ +public class BodyExtractorsTests { + + @Test + public void toMono() throws Exception { + BodyExtractor> extractor = BodyExtractors.toMono(String.class); + + DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); + DefaultDataBuffer dataBuffer = + factory.wrap(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8))); + Flux body = Flux.just(dataBuffer); + + MockServerHttpRequest request = new MockServerHttpRequest(); + request.setBody(body); + + Configuration configuration = Configuration.builder().build(); + + Mono result = extractor.extract(request, configuration); + + TestSubscriber.subscribe(result) + .assertComplete() + .assertValues("foo"); + } + + @Test + public void toFlux() throws Exception { + BodyExtractor> extractor = BodyExtractors.toFlux(String.class); + + DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); + DefaultDataBuffer dataBuffer = + factory.wrap(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8))); + Flux body = Flux.just(dataBuffer); + + MockServerHttpRequest request = new MockServerHttpRequest(); + request.setBody(body); + + Configuration configuration = Configuration.builder().build(); + + Flux result = extractor.extract(request, configuration); + TestSubscriber.subscribe(result) + .assertComplete() + .assertValues("foo"); + } + + @Test + public void toFluxUnacceptable() throws Exception { + BodyExtractor> extractor = BodyExtractors.toFlux(String.class); + + DefaultDataBufferFactory factory = new DefaultDataBufferFactory(); + DefaultDataBuffer dataBuffer = + factory.wrap(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8))); + Flux body = Flux.just(dataBuffer); + + MockServerHttpRequest request = new MockServerHttpRequest(); + request.getHeaders().setContentType(MediaType.APPLICATION_JSON); + request.setBody(body); + + Configuration configuration = Configuration.empty().build(); + + Flux result = extractor.extract(request, configuration); + TestSubscriber.subscribe(result) + .assertError(UnsupportedMediaTypeStatusException.class); + + } + +} \ No newline at end of file diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyPopulatorsTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyPopulatorsTests.java new file mode 100644 index 0000000000..0356eea9a5 --- /dev/null +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyPopulatorsTests.java @@ -0,0 +1,142 @@ +/* + * Copyright 2002-2016 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; + +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.util.function.BiFunction; + +import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.codec.ServerSentEvent; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.mock.http.server.reactive.test.MockServerHttpResponse; +import org.springframework.tests.TestSubscriber; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +/** + * @author Arjen Poutsma + */ +public class BodyPopulatorsTests { + + @Test + public void ofObject() throws Exception { + String body = "foo"; + BodyPopulator populator = BodyPopulators.fromObject(body); + + assertEquals(body, populator.supplier().get()); + + BiFunction> writer = populator.writer(); + MockServerHttpResponse response = new MockServerHttpResponse(); + Mono result = writer.apply(response, Configuration.builder().build()); + TestSubscriber.subscribe(result) + .assertComplete(); + + ByteBuffer byteBuffer = ByteBuffer.wrap(body.getBytes(UTF_8)); + DataBuffer buffer = new DefaultDataBufferFactory().wrap(byteBuffer); + TestSubscriber.subscribe(response.getBody()) + .assertComplete() + .assertValues(buffer); + } + + @Test + public void ofPublisher() throws Exception { + Flux body = Flux.just("foo"); + BodyPopulator> populator = BodyPopulators.fromPublisher(body, String.class); + + assertEquals(body, populator.supplier().get()); + + BiFunction> writer = populator.writer(); + MockServerHttpResponse response = new MockServerHttpResponse(); + Mono result = writer.apply(response, Configuration.builder().build()); + TestSubscriber.subscribe(result) + .assertComplete(); + + ByteBuffer byteBuffer = ByteBuffer.wrap("foo".getBytes(UTF_8)); + DataBuffer buffer = new DefaultDataBufferFactory().wrap(byteBuffer); + TestSubscriber.subscribe(response.getBody()) + .assertComplete() + .assertValues(buffer); + } + + @Test + public void ofResource() throws Exception { + Resource body = new ClassPathResource("response.txt", getClass()); + BodyPopulator populator = BodyPopulators.fromResource(body); + + assertEquals(body, populator.supplier().get()); + + BiFunction> writer = populator.writer(); + MockServerHttpResponse response = new MockServerHttpResponse(); + Mono result = writer.apply(response, Configuration.builder().build()); + TestSubscriber.subscribe(result) + .assertComplete(); + + byte[] expectedBytes = Files.readAllBytes(body.getFile().toPath()); + + TestSubscriber.subscribe(response.getBody()) + .assertComplete() + .assertValuesWith(dataBuffer -> { + byte[] resultBytes = new byte[dataBuffer.readableByteCount()]; + dataBuffer.read(resultBytes); + assertArrayEquals(expectedBytes, resultBytes); + }); + } + + @Test + public void ofServerSentEventFlux() throws Exception { + ServerSentEvent event = ServerSentEvent.builder("foo").build(); + Flux> body = Flux.just(event); + BodyPopulator>> populator = + BodyPopulators.fromServerSentEvents(body); + + assertEquals(body, populator.supplier().get()); + + BiFunction> writer = populator.writer(); + MockServerHttpResponse response = new MockServerHttpResponse(); + Mono result = writer.apply(response, Configuration.builder().build()); + TestSubscriber.subscribe(result) + .assertComplete(); + + } + + @Test + public void ofServerSentEventClass() throws Exception { + Flux body = Flux.just("foo"); + BodyPopulator> populator = + BodyPopulators.fromServerSentEvents(body, String.class); + + assertEquals(body, populator.supplier().get()); + + BiFunction> writer = populator.writer(); + MockServerHttpResponse response = new MockServerHttpResponse(); + Mono result = writer.apply(response, Configuration.builder().build()); + TestSubscriber.subscribe(result) + .assertComplete(); + + } + +} \ No newline at end of file diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyWrapperTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyWrapperTests.java deleted file mode 100644 index 9262c7e3ce..0000000000 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/BodyWrapperTests.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2002-2016 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; - -import org.junit.Before; -import org.junit.Test; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.core.io.buffer.DefaultDataBufferFactory; -import org.springframework.web.reactive.function.support.RequestWrapper; - -import static org.junit.Assert.assertSame; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -/** - * @author Arjen Poutsma - */ -public class BodyWrapperTests { - - private Request.Body mockBody; - - private RequestWrapper.BodyWrapper wrapper; - - @Before - public void setUp() throws Exception { - mockBody = mock(Request.Body.class); - wrapper = new RequestWrapper.BodyWrapper(mockBody); - } - - @Test - public void stream() throws Exception { - DataBuffer buffer = new DefaultDataBufferFactory().allocateBuffer(); - Flux flux = Flux.just(buffer); - when(mockBody.stream()).thenReturn(flux); - - assertSame(flux, wrapper.stream()); - } - - @Test - public void convertTo() throws Exception { - Flux flux = Flux.just("foo", "bar"); - when(mockBody.convertTo(String.class)).thenReturn(flux); - - assertSame(flux, wrapper.convertTo(String.class)); - } - - @Test - public void convertToMono() throws Exception { - Mono mono = Mono.just("foo"); - when(mockBody.convertToMono(String.class)).thenReturn(mono); - - assertSame(mono, wrapper.convertToMono(String.class)); - } - -} \ No newline at end of file diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultRequestTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultRequestTests.java index f5acad0a35..e57dcbd29d 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultRequestTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultRequestTests.java @@ -27,8 +27,6 @@ import java.util.Map; import java.util.Optional; import java.util.OptionalLong; import java.util.Set; -import java.util.function.Supplier; -import java.util.stream.Stream; import org.junit.Before; import org.junit.Test; @@ -54,6 +52,7 @@ import org.springframework.web.server.ServerWebExchange; import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import static org.springframework.web.reactive.function.BodyExtractors.toMono; /** * @author Arjen Poutsma @@ -66,6 +65,8 @@ public class DefaultRequestTests { private ServerWebExchange mockExchange; + private Configuration mockConfiguration; + private DefaultRequest defaultRequest; @Before @@ -76,8 +77,9 @@ public class DefaultRequestTests { mockExchange = mock(ServerWebExchange.class); when(mockExchange.getRequest()).thenReturn(mockRequest); when(mockExchange.getResponse()).thenReturn(mockResponse); + mockConfiguration = mock(Configuration.class); - defaultRequest = new DefaultRequest(mockExchange); + defaultRequest = new DefaultRequest(mockExchange, mockConfiguration); } @Test @@ -112,6 +114,14 @@ public class DefaultRequestTests { assertEquals(Optional.of("bar"), defaultRequest.queryParam("foo")); } + @Test + public void pathVariable() throws Exception { + Map pathVariables = Collections.singletonMap("foo", "bar"); + when(mockExchange.getAttribute(RoutingFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE)).thenReturn(Optional.of(pathVariables)); + + assertEquals(Optional.of("bar"), defaultRequest.pathVariable("foo")); + } + @Test public void pathVariables() throws Exception { Map pathVariables = Collections.singletonMap("foo", "bar"); @@ -161,14 +171,9 @@ public class DefaultRequestTests { Set> messageReaders = Collections .singleton(new DecoderHttpMessageReader(new StringDecoder())); - Configuration mockConfig = mock(Configuration.class); - when(mockConfig.messageReaders()).thenReturn(messageReaders::stream); - when(mockExchange.getAttribute(RoutingFunctions.CONFIGURATION_ATTRIBUTE)) - .thenReturn(Optional.of(mockConfig)); + when(mockConfiguration.messageReaders()).thenReturn(messageReaders::stream); - assertEquals(body, defaultRequest.body().stream()); - - Mono resultMono = defaultRequest.body().convertToMono(String.class); + Mono resultMono = defaultRequest.body(toMono(String.class)); assertEquals("foo", resultMono.block()); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DispatcherHandlerIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DispatcherHandlerIntegrationTests.java index d5a1c796e8..ede25383f3 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DispatcherHandlerIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DispatcherHandlerIntegrationTests.java @@ -50,7 +50,6 @@ import org.springframework.web.reactive.result.view.ViewResolver; import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import static org.junit.Assert.assertEquals; -import static org.springframework.web.reactive.function.BodyPopulators.ofPublisher; import static org.springframework.web.reactive.function.RoutingFunctions.route; /** @@ -156,13 +155,14 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr public Response> mono(Request request) { Person person = new Person("John"); - return Response.ok().body(ofPublisher(Mono.just(person), Person.class)); + return Response.ok().body(BodyPopulators.fromPublisher(Mono.just(person), Person.class)); } public Response> flux(Request request) { Person person1 = new Person("John"); Person person2 = new Person("Jane"); - return Response.ok().body(ofPublisher(Flux.just(person1, person2), Person.class)); + return Response.ok().body( + BodyPopulators.fromPublisher(Flux.just(person1, person2), Person.class)); } } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/MockRequest.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/MockRequest.java index 3c6cd171dc..ebb3bb1d62 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/MockRequest.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/MockRequest.java @@ -29,10 +29,6 @@ import java.util.Map; import java.util.Optional; import java.util.OptionalLong; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - -import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.HttpRange; @@ -44,7 +40,7 @@ import org.springframework.util.MultiValueMap; /** * @author Arjen Poutsma */ -public class MockRequest implements Request { +public class MockRequest implements Request { private final HttpMethod method; @@ -52,7 +48,7 @@ public class MockRequest implements Request { private final MockHeaders headers; - private final MockBody body; + private final T body; private final Map attributes; @@ -61,7 +57,7 @@ public class MockRequest implements Request { private final Map pathVariables; private MockRequest(HttpMethod method, URI uri, - MockHeaders headers, MockBody body, Map attributes, + MockHeaders headers, T body, Map attributes, MultiValueMap queryParams, Map pathVariables) { this.method = method; @@ -73,8 +69,8 @@ public class MockRequest implements Request { this.pathVariables = pathVariables; } - public static Builder builder() { - return new BuilderImpl(); + public static Builder builder() { + return new BuilderImpl(); } @Override @@ -92,15 +88,16 @@ public class MockRequest implements Request { return this.headers; } + @SuppressWarnings("unchecked") @Override - public Body body() { - return this.body; + public S body(BodyExtractor extractor) { + return (S) this.body; } @SuppressWarnings("unchecked") @Override - public Optional attribute(String name) { - return Optional.ofNullable((T) this.attributes.get(name)); + public Optional attribute(String name) { + return Optional.ofNullable((S) this.attributes.get(name)); } @Override @@ -113,37 +110,35 @@ public class MockRequest implements Request { return Collections.unmodifiableMap(this.pathVariables); } - public interface Builder { + public interface Builder { - Builder method(HttpMethod method); + Builder method(HttpMethod method); - Builder uri(URI uri); + Builder uri(URI uri); - Builder header(String key, String value); + Builder header(String key, String value); - Builder headers(HttpHeaders headers); + Builder headers(HttpHeaders headers); - Builder attribute(String name, Object value); + Builder attribute(String name, Object value); - Builder attributes(Map attributes); + Builder attributes(Map attributes); - Builder queryParam(String key, String value); + Builder queryParam(String key, String value); - Builder queryParams(MultiValueMap queryParams); + Builder queryParams(MultiValueMap queryParams); - Builder pathVariable(String key, String value); + Builder pathVariable(String key, String value); - Builder pathVariables(Map pathVariables); + Builder pathVariables(Map pathVariables); - MockRequest body(Flux body); + MockRequest body(T body); - MockRequest body(Mono body); - - MockRequest build(); + MockRequest build(); } - private static class BuilderImpl implements Builder { + private static class BuilderImpl implements Builder { private HttpMethod method = HttpMethod.GET; @@ -151,6 +146,8 @@ public class MockRequest implements Request { private MockHeaders headers = new MockHeaders(new HttpHeaders()); + private T body; + private Map attributes = new LinkedHashMap<>(); private MultiValueMap queryParams = new LinkedMultiValueMap<>(); @@ -158,21 +155,21 @@ public class MockRequest implements Request { private Map pathVariables = new LinkedHashMap<>(); @Override - public Builder method(HttpMethod method) { + public Builder method(HttpMethod method) { Assert.notNull(method, "'method' must not be null"); this.method = method; return this; } @Override - public Builder uri(URI uri) { + public Builder uri(URI uri) { Assert.notNull(uri, "'uri' must not be null"); this.uri = uri; return this; } @Override - public Builder header(String key, String value) { + public Builder header(String key, String value) { Assert.notNull(key, "'key' must not be null"); Assert.notNull(value, "'value' must not be null"); this.headers.header(key, value); @@ -180,14 +177,14 @@ public class MockRequest implements Request { } @Override - public Builder headers(HttpHeaders headers) { + public Builder headers(HttpHeaders headers) { Assert.notNull(headers, "'headers' must not be null"); this.headers = new MockHeaders(headers); return this; } @Override - public Builder attribute(String name, Object value) { + public Builder attribute(String name, Object value) { Assert.notNull(name, "'name' must not be null"); Assert.notNull(value, "'value' must not be null"); this.attributes.put(name, value); @@ -195,14 +192,14 @@ public class MockRequest implements Request { } @Override - public Builder attributes(Map attributes) { + public Builder attributes(Map attributes) { Assert.notNull(attributes, "'attributes' must not be null"); this.attributes = attributes; return this; } @Override - public Builder queryParam(String key, String value) { + public Builder queryParam(String key, String value) { Assert.notNull(key, "'key' must not be null"); Assert.notNull(value, "'value' must not be null"); this.queryParams.add(key, value); @@ -210,14 +207,14 @@ public class MockRequest implements Request { } @Override - public Builder queryParams(MultiValueMap queryParams) { + public Builder queryParams(MultiValueMap queryParams) { Assert.notNull(queryParams, "'queryParams' must not be null"); this.queryParams = queryParams; return this; } @Override - public Builder pathVariable(String key, String value) { + public Builder pathVariable(String key, String value) { Assert.notNull(key, "'key' must not be null"); Assert.notNull(value, "'value' must not be null"); this.pathVariables.put(key, value); @@ -225,45 +222,25 @@ public class MockRequest implements Request { } @Override - public Builder pathVariables(Map pathVariables) { + public Builder pathVariables(Map pathVariables) { Assert.notNull(pathVariables, "'pathVariables' must not be null"); this.pathVariables = pathVariables; return this; } @Override - public MockRequest body(Flux flux) { - MockBody body = new MockBody() { - @SuppressWarnings("unchecked") - @Override - public Flux convertTo(Class aClass) { - return (Flux) flux; - } - }; - return build(body); + public MockRequest body(T body) { + this.body = body; + return new MockRequest(this.method, this.uri, this.headers, this.body, + this.attributes, this.queryParams, this.pathVariables); } @Override - public MockRequest body(Mono mono) { - MockBody body = new MockBody() { - @SuppressWarnings("unchecked") - @Override - public Mono convertToMono(Class aClass) { - return (Mono) mono; - } - }; - return build(body); + public MockRequest build() { + return new MockRequest(this.method, this.uri, this.headers, null, + this.attributes, this.queryParams, this.pathVariables); } - @Override - public MockRequest build() { - return build(new MockBody()); - } - - private MockRequest build(MockBody body) { - return new MockRequest(this.method, this.uri, this.headers, body, this.attributes, - this.queryParams, this.pathVariables); - } } private static class MockHeaders implements Headers { @@ -339,24 +316,4 @@ public class MockRequest implements Request { } } - private static class MockBody implements Body { - - @Override - public Flux stream() { - return Flux.empty(); - } - - @Override - public Flux convertTo(Class aClass) { - return Flux.empty(); - } - - @Override - public Mono convertToMono(Class aClass) { - return Mono.empty(); - } - } - - - } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/PublisherHandlerFunctionIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/PublisherHandlerFunctionIntegrationTests.java index e87071cac0..8710025df1 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/PublisherHandlerFunctionIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/PublisherHandlerFunctionIntegrationTests.java @@ -33,7 +33,7 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.client.RestTemplate; import static org.junit.Assert.assertEquals; -import static org.springframework.web.reactive.function.BodyPopulators.ofPublisher; +import static org.springframework.web.reactive.function.BodyExtractors.toMono; import static org.springframework.web.reactive.function.RequestPredicates.GET; import static org.springframework.web.reactive.function.RequestPredicates.POST; import static org.springframework.web.reactive.function.RoutingFunctions.route; @@ -98,18 +98,19 @@ public class PublisherHandlerFunctionIntegrationTests public Response> mono(Request request) { Person person = new Person("John"); - return Response.ok().body(ofPublisher(Mono.just(person), Person.class)); + return Response.ok().body(BodyPopulators.fromPublisher(Mono.just(person), Person.class)); } public Response> postMono(Request request) { - Mono personMono = request.body().convertToMono(Person.class); - return Response.ok().body(ofPublisher(personMono, Person.class)); + Mono personMono = request.body(toMono(Person.class)); + return Response.ok().body(BodyPopulators.fromPublisher(personMono, Person.class)); } public Response> flux(Request request) { Person person1 = new Person("John"); Person person2 = new Person("Jane"); - return Response.ok().body(ofPublisher(Flux.just(person1, person2), Person.class)); + return Response.ok().body( + BodyPopulators.fromPublisher(Flux.just(person1, person2), Person.class)); } } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RequestWrapperTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RequestWrapperTests.java index 0d620e44bd..f21468c703 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RequestWrapperTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RequestWrapperTests.java @@ -85,14 +85,6 @@ public class RequestWrapperTests { assertSame(headers, wrapper.headers()); } - @Test - public void body() throws Exception { - Request.Body body = mock(Request.Body.class); - when(mockRequest.body()).thenReturn(body); - - assertEquals(body, wrapper.body()); - } - @Test public void attribute() throws Exception { String name = "foo"; diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RoutingFunctionTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RoutingFunctionTests.java index 75ede96560..1d422ddc01 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RoutingFunctionTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/RoutingFunctionTests.java @@ -23,7 +23,7 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import static org.springframework.web.reactive.function.BodyPopulators.ofObject; +import static org.springframework.web.reactive.function.BodyPopulators.fromObject; /** * @author Arjen Poutsma @@ -48,7 +48,7 @@ public class RoutingFunctionTests { @Test public void and() throws Exception { - HandlerFunction handlerFunction = request -> Response.ok().body(ofObject("42")); + HandlerFunction handlerFunction = request -> Response.ok().body(fromObject("42")); RoutingFunction routingFunction1 = request -> Optional.empty(); RoutingFunction routingFunction2 = request -> Optional.of(handlerFunction); @@ -63,13 +63,13 @@ public class RoutingFunctionTests { @Test public void filter() throws Exception { - HandlerFunction handlerFunction = request -> Response.ok().body(ofObject("42")); + HandlerFunction handlerFunction = request -> Response.ok().body(fromObject("42")); RoutingFunction routingFunction = request -> Optional.of(handlerFunction); FilterFunction filterFunction = (request, next) -> { Response response = next.handle(request); int i = Integer.parseInt(response.body()); - return Response.ok().body(ofObject(i)); + return Response.ok().body(fromObject(i)); }; RoutingFunction result = routingFunction.filter(filterFunction); assertNotNull(result); diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/SseHandlerFunctionIntegrationTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/SseHandlerFunctionIntegrationTests.java index 36a4746420..03524097ec 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/SseHandlerFunctionIntegrationTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/SseHandlerFunctionIntegrationTests.java @@ -32,7 +32,6 @@ import org.springframework.web.client.reactive.WebClient; import static org.springframework.web.client.reactive.ClientWebRequestBuilders.get; import static org.springframework.web.client.reactive.ResponseExtractors.bodyStream; -import static org.springframework.web.reactive.function.BodyPopulators.ofServerSentEvents; import static org.springframework.web.reactive.function.RoutingFunctions.route; /** @@ -112,13 +111,13 @@ public class SseHandlerFunctionIntegrationTests public Response> string(Request request) { Flux flux = Flux.interval(Duration.ofMillis(100)).map(l -> "foo " + l).take(2); - return Response.ok().body(ofServerSentEvents(flux, String.class)); + return Response.ok().body(BodyPopulators.fromServerSentEvents(flux, String.class)); } public Response> person(Request request) { Flux flux = Flux.interval(Duration.ofMillis(100)) .map(l -> new Person("foo " + l)).take(2); - return Response.ok().body(ofServerSentEvents(flux, Person.class)); + return Response.ok().body(BodyPopulators.fromServerSentEvents(flux, Person.class)); } public Response>> sse(Request request) { @@ -128,7 +127,7 @@ public class SseHandlerFunctionIntegrationTests .comment("bar") .build()).take(2); - return Response.ok().body(ofServerSentEvents(flux)); + return Response.ok().body(BodyPopulators.fromServerSentEvents(flux)); } }