Rename Configuration to StrategiesSupplier
This commit is contained in:
@@ -33,9 +33,9 @@ public interface BodyExtractor<T> {
|
||||
/**
|
||||
* Extract from the given request.
|
||||
* @param request the request to extract from
|
||||
* @param configuration the configuration to use
|
||||
* @param strategies the strategies to use
|
||||
* @return the extracted data
|
||||
*/
|
||||
T extract(ServerHttpRequest request, Configuration configuration);
|
||||
T extract(ServerHttpRequest request, StrategiesSupplier strategies);
|
||||
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ public abstract class BodyExtractors {
|
||||
*/
|
||||
public static <T> BodyExtractor<Mono<T>> toMono(ResolvableType elementType) {
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
return (request, configuration) -> readWithMessageReaders(request, configuration,
|
||||
return (request, strategies) -> readWithMessageReaders(request, strategies,
|
||||
elementType,
|
||||
reader -> reader.readMono(elementType, request, Collections.emptyMap()),
|
||||
Mono::error);
|
||||
@@ -86,7 +86,7 @@ public abstract class BodyExtractors {
|
||||
*/
|
||||
public static <T> BodyExtractor<Flux<T>> toFlux(ResolvableType elementType) {
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
return (request, configuration) -> readWithMessageReaders(request, configuration,
|
||||
return (request, strategies) -> readWithMessageReaders(request, strategies,
|
||||
elementType,
|
||||
reader -> reader.read(elementType, request, Collections.emptyMap()),
|
||||
Flux::error);
|
||||
@@ -94,14 +94,13 @@ public abstract class BodyExtractors {
|
||||
|
||||
private static <T, S extends Publisher<T>> S readWithMessageReaders(
|
||||
ServerHttpRequest request,
|
||||
Configuration configuration,
|
||||
StrategiesSupplier strategies,
|
||||
ResolvableType elementType,
|
||||
Function<HttpMessageReader<T>, S> readerFunction,
|
||||
Function<Throwable, S> unsupportedError) {
|
||||
|
||||
MediaType contentType = contentType(request);
|
||||
Supplier<Stream<HttpMessageReader<?>>> messageReaders =
|
||||
configuration.messageReaders();
|
||||
Supplier<Stream<HttpMessageReader<?>>> messageReaders = strategies.messageReaders();
|
||||
return messageReaders.get()
|
||||
.filter(r -> r.canRead(elementType, contentType, Collections.emptyMap()))
|
||||
.findFirst()
|
||||
|
||||
@@ -39,10 +39,10 @@ public interface BodyInserter<T> {
|
||||
/**
|
||||
* Insert into the given response.
|
||||
* @param response the response to insert into
|
||||
* @param configuration the configuration to use
|
||||
* @param strategies the strategies to use
|
||||
* @return a {@code Mono} that indicates completion or error
|
||||
*/
|
||||
Mono<Void> insert(ServerHttpResponse response, Configuration configuration);
|
||||
Mono<Void> insert(ServerHttpResponse response, StrategiesSupplier strategies);
|
||||
|
||||
/**
|
||||
* Return the type contained in the body.
|
||||
@@ -58,7 +58,7 @@ public interface BodyInserter<T> {
|
||||
* @param <T> the type supplied and written by the inserter
|
||||
* @return the new {@code BodyInserter}
|
||||
*/
|
||||
static <T> BodyInserter<T> of(BiFunction<ServerHttpResponse, Configuration, Mono<Void>> writer,
|
||||
static <T> BodyInserter<T> of(BiFunction<ServerHttpResponse, StrategiesSupplier, Mono<Void>> writer,
|
||||
Supplier<T> supplier) {
|
||||
|
||||
Assert.notNull(writer, "'writer' must not be null");
|
||||
|
||||
@@ -64,7 +64,7 @@ public abstract class BodyInserters {
|
||||
public static <T> BodyInserter<T> fromObject(T body) {
|
||||
Assert.notNull(body, "'body' must not be null");
|
||||
return BodyInserter.of(
|
||||
(response, configuration) -> writeWithMessageWriters(response, configuration,
|
||||
(response, strategies) -> writeWithMessageWriters(response, strategies,
|
||||
Mono.just(body), ResolvableType.forInstance(body)),
|
||||
() -> body);
|
||||
}
|
||||
@@ -99,7 +99,7 @@ public abstract class BodyInserters {
|
||||
Assert.notNull(publisher, "'publisher' must not be null");
|
||||
Assert.notNull(elementType, "'elementType' must not be null");
|
||||
return BodyInserter.of(
|
||||
(response, configuration) -> writeWithMessageWriters(response, configuration,
|
||||
(response, strategies) -> writeWithMessageWriters(response, strategies,
|
||||
publisher, elementType),
|
||||
() -> publisher
|
||||
);
|
||||
@@ -117,7 +117,7 @@ public abstract class BodyInserters {
|
||||
public static <T extends Resource> BodyInserter<T> fromResource(T resource) {
|
||||
Assert.notNull(resource, "'resource' must not be null");
|
||||
return BodyInserter.of(
|
||||
(response, configuration) -> {
|
||||
(response, strategies) -> {
|
||||
ResourceHttpMessageWriter messageWriter = new ResourceHttpMessageWriter();
|
||||
MediaType contentType = response.getHeaders().getContentType();
|
||||
return messageWriter.write(Mono.just(resource), RESOURCE_TYPE, contentType,
|
||||
@@ -139,7 +139,7 @@ public abstract class BodyInserters {
|
||||
|
||||
Assert.notNull(eventsPublisher, "'eventsPublisher' must not be null");
|
||||
return BodyInserter.of(
|
||||
(response, configuration) -> {
|
||||
(response, strategies) -> {
|
||||
ServerSentEventHttpMessageWriter messageWriter = sseMessageWriter();
|
||||
MediaType contentType = response.getHeaders().getContentType();
|
||||
return messageWriter.write(eventsPublisher, SERVER_SIDE_EVENT_TYPE,
|
||||
@@ -183,7 +183,7 @@ public abstract class BodyInserters {
|
||||
Assert.notNull(eventsPublisher, "'eventsPublisher' must not be null");
|
||||
Assert.notNull(eventType, "'eventType' must not be null");
|
||||
return BodyInserter.of(
|
||||
(response, configuration) -> {
|
||||
(response, strategies) -> {
|
||||
ServerSentEventHttpMessageWriter messageWriter = sseMessageWriter();
|
||||
MediaType contentType = response.getHeaders().getContentType();
|
||||
return messageWriter.write(eventsPublisher, eventType, contentType, response,
|
||||
@@ -201,13 +201,13 @@ public abstract class BodyInserters {
|
||||
}
|
||||
|
||||
private static <T> Mono<Void> writeWithMessageWriters(ServerHttpResponse response,
|
||||
Configuration configuration,
|
||||
StrategiesSupplier strategies,
|
||||
Publisher<T> body,
|
||||
ResolvableType bodyType) {
|
||||
|
||||
// TODO: use ContentNegotiatingResultHandlerSupport
|
||||
MediaType contentType = response.getHeaders().getContentType();
|
||||
return configuration.messageWriters().get()
|
||||
return strategies.messageWriters().get()
|
||||
.filter(messageWriter -> messageWriter.canWrite(bodyType, contentType, Collections
|
||||
.emptyMap()))
|
||||
.findFirst()
|
||||
@@ -228,20 +228,20 @@ public abstract class BodyInserters {
|
||||
|
||||
static class DefaultBodyInserter<T> implements BodyInserter<T> {
|
||||
|
||||
private final BiFunction<ServerHttpResponse, Configuration, Mono<Void>> writer;
|
||||
private final BiFunction<ServerHttpResponse, StrategiesSupplier, Mono<Void>> writer;
|
||||
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
public DefaultBodyInserter(
|
||||
BiFunction<ServerHttpResponse, Configuration, Mono<Void>> writer,
|
||||
BiFunction<ServerHttpResponse, StrategiesSupplier, Mono<Void>> writer,
|
||||
Supplier<T> supplier) {
|
||||
this.writer = writer;
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> insert(ServerHttpResponse response, Configuration configuration) {
|
||||
return this.writer.apply(response, configuration);
|
||||
public Mono<Void> insert(ServerHttpResponse response, StrategiesSupplier strategies) {
|
||||
return this.writer.apply(response, strategies);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,11 +42,11 @@ class DefaultRequest implements Request {
|
||||
|
||||
private final Headers headers;
|
||||
|
||||
private final Configuration configuration;
|
||||
private final StrategiesSupplier strategies;
|
||||
|
||||
DefaultRequest(ServerWebExchange exchange, Configuration configuration) {
|
||||
DefaultRequest(ServerWebExchange exchange, StrategiesSupplier strategies) {
|
||||
this.exchange = exchange;
|
||||
this.configuration = configuration;
|
||||
this.strategies = strategies;
|
||||
this.headers = new DefaultHeaders();
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ class DefaultRequest implements Request {
|
||||
|
||||
@Override
|
||||
public <T> T body(BodyExtractor<T> extractor) {
|
||||
return extractor.extract(request(), this.configuration);
|
||||
return extractor.extract(request(), this.strategies);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -142,7 +142,7 @@ class DefaultResponseBuilder implements Response.BodyBuilder {
|
||||
@Override
|
||||
public Response<Void> build() {
|
||||
return body(BodyInserter.of(
|
||||
(response, configuration) -> response.setComplete(),
|
||||
(response, strategies) -> response.setComplete(),
|
||||
() -> null));
|
||||
}
|
||||
|
||||
@@ -150,12 +150,12 @@ class DefaultResponseBuilder implements Response.BodyBuilder {
|
||||
public <T extends Publisher<Void>> Response<T> build(T voidPublisher) {
|
||||
Assert.notNull(voidPublisher, "'voidPublisher' must not be null");
|
||||
return body(BodyInserter.of(
|
||||
(response, configuration) -> Flux.from(voidPublisher).then(response.setComplete()),
|
||||
(response, strategies) -> Flux.from(voidPublisher).then(response.setComplete()),
|
||||
() -> null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Response<T> body(BiFunction<ServerHttpResponse, Configuration, Mono<Void>> writer,
|
||||
public <T> Response<T> body(BiFunction<ServerHttpResponse, StrategiesSupplier, Mono<Void>> writer,
|
||||
Supplier<T> supplier) {
|
||||
return body(BodyInserter.of(writer, supplier));
|
||||
}
|
||||
@@ -250,10 +250,10 @@ class DefaultResponseBuilder implements Response.BodyBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> writeTo(ServerWebExchange exchange, Configuration configuration) {
|
||||
public Mono<Void> writeTo(ServerWebExchange exchange, StrategiesSupplier strategies) {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
writeStatusAndHeaders(response);
|
||||
return this.inserter.insert(response, configuration);
|
||||
return this.inserter.insert(response, strategies);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -281,12 +281,12 @@ class DefaultResponseBuilder implements Response.BodyBuilder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> writeTo(ServerWebExchange exchange, Configuration configuration) {
|
||||
public Mono<Void> writeTo(ServerWebExchange exchange, StrategiesSupplier strategies) {
|
||||
ServerHttpResponse response = exchange.getResponse();
|
||||
writeStatusAndHeaders(response);
|
||||
MediaType contentType = exchange.getResponse().getHeaders().getContentType();
|
||||
Locale locale = Locale.ENGLISH; // TODO: resolve locale
|
||||
Stream<ViewResolver> viewResolverStream = configuration.viewResolvers().get();
|
||||
Stream<ViewResolver> viewResolverStream = strategies.viewResolvers().get();
|
||||
return Flux.fromStream(viewResolverStream)
|
||||
.concatMap(viewResolver -> viewResolver.resolveViewName(this.name, locale))
|
||||
.next()
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.web.reactive.function;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
@@ -41,20 +40,22 @@ import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link StrategiesSupplier.Builder}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.0
|
||||
*/
|
||||
class DefaultConfigurationBuilder implements Configuration.Builder {
|
||||
class DefaultStrategiesSupplierBuilder implements StrategiesSupplier.Builder {
|
||||
|
||||
private static final boolean jackson2Present =
|
||||
ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper",
|
||||
DefaultConfigurationBuilder.class.getClassLoader()) &&
|
||||
DefaultStrategiesSupplierBuilder.class.getClassLoader()) &&
|
||||
ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator",
|
||||
DefaultConfigurationBuilder.class.getClassLoader());
|
||||
DefaultStrategiesSupplierBuilder.class.getClassLoader());
|
||||
|
||||
private static final boolean jaxb2Present =
|
||||
ClassUtils.isPresent("javax.xml.bind.Binder",
|
||||
DefaultConfigurationBuilder.class.getClassLoader());
|
||||
DefaultStrategiesSupplierBuilder.class.getClassLoader());
|
||||
|
||||
|
||||
private final List<HttpMessageReader<?>> messageReaders = new ArrayList<>();
|
||||
@@ -85,33 +86,33 @@ class DefaultConfigurationBuilder implements Configuration.Builder {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration.Builder messageReader(HttpMessageReader<?> messageReader) {
|
||||
public StrategiesSupplier.Builder messageReader(HttpMessageReader<?> messageReader) {
|
||||
Assert.notNull(messageReader, "'messageReader' must not be null");
|
||||
this.messageReaders.add(messageReader);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration.Builder messageWriter(HttpMessageWriter<?> messageWriter) {
|
||||
public StrategiesSupplier.Builder messageWriter(HttpMessageWriter<?> messageWriter) {
|
||||
Assert.notNull(messageWriter, "'messageWriter' must not be null");
|
||||
this.messageWriters.add(messageWriter);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration.Builder viewResolver(ViewResolver viewResolver) {
|
||||
public StrategiesSupplier.Builder viewResolver(ViewResolver viewResolver) {
|
||||
Assert.notNull(viewResolver, "'viewResolver' must not be null");
|
||||
this.viewResolvers.add(viewResolver);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configuration build() {
|
||||
return new DefaultConfiguration(this.messageReaders, this.messageWriters,
|
||||
public StrategiesSupplier build() {
|
||||
return new DefaultStrategiesSupplier(this.messageReaders, this.messageWriters,
|
||||
this.viewResolvers);
|
||||
}
|
||||
|
||||
private static class DefaultConfiguration implements Configuration {
|
||||
private static class DefaultStrategiesSupplier implements StrategiesSupplier {
|
||||
|
||||
private final List<HttpMessageReader<?>> messageReaders;
|
||||
|
||||
@@ -119,7 +120,7 @@ class DefaultConfigurationBuilder implements Configuration.Builder {
|
||||
|
||||
private final List<ViewResolver> viewResolvers;
|
||||
|
||||
public DefaultConfiguration(
|
||||
public DefaultStrategiesSupplier(
|
||||
List<HttpMessageReader<?>> messageReaders,
|
||||
List<HttpMessageWriter<?>> messageWriters,
|
||||
List<ViewResolver> viewResolvers) {
|
||||
@@ -67,9 +67,10 @@ public interface Response<T> {
|
||||
* Writes this response to the given web exchange.
|
||||
*
|
||||
* @param exchange the web exchange to write to
|
||||
* @param strategies the strategies to use when writing
|
||||
* @return {@code Mono<Void>} to indicate when request handling is complete
|
||||
*/
|
||||
Mono<Void> writeTo(ServerWebExchange exchange, Configuration configuration);
|
||||
Mono<Void> writeTo(ServerWebExchange exchange, StrategiesSupplier strategies);
|
||||
|
||||
// Static builder methods
|
||||
|
||||
@@ -315,7 +316,7 @@ public interface Response<T> {
|
||||
* @param <T> the type contained in the body
|
||||
* @return the built response
|
||||
*/
|
||||
<T> Response<T> body(BiFunction<ServerHttpResponse, Configuration, Mono<Void>> writer,
|
||||
<T> Response<T> body(BiFunction<ServerHttpResponse, StrategiesSupplier, Mono<Void>> writer,
|
||||
Supplier<T> supplier);
|
||||
|
||||
/**
|
||||
|
||||
@@ -38,7 +38,7 @@ import org.springframework.web.server.adapter.HttpWebHandlerAdapter;
|
||||
* <p>Additionally, this class can {@linkplain #toHttpHandler(RouterFunction) transform} a
|
||||
* {@code RouterFunction} into an {@code HttpHandler}, which can be run in Servlet 3.1+,
|
||||
* Reactor, RxNetty, or Undertow.
|
||||
* And it can {@linkplain #toHandlerMapping(RouterFunction, Configuration) transform} a
|
||||
* And it can {@linkplain #toHandlerMapping(RouterFunction, StrategiesSupplier) transform} a
|
||||
* {@code RouterFunction} into an {@code HandlerMapping}, which can be run in a
|
||||
* {@code DispatcherHandler}.
|
||||
*
|
||||
@@ -103,7 +103,7 @@ public abstract class RouterFunctions {
|
||||
|
||||
/**
|
||||
* Converts the given {@linkplain RouterFunction routing function} into a {@link HttpHandler}.
|
||||
* This conversion uses the {@linkplain Configuration#builder() default configuration}.
|
||||
* This conversion uses {@linkplain StrategiesSupplier#builder() default strategies}.
|
||||
*
|
||||
* <p>The returned {@code HttpHandler} can be adapted to run in
|
||||
* <ul>
|
||||
@@ -121,12 +121,12 @@ public abstract class RouterFunctions {
|
||||
* @return an http handler that handles HTTP request using the given routing function
|
||||
*/
|
||||
public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction) {
|
||||
return toHttpHandler(routerFunction, defaultConfiguration());
|
||||
return toHttpHandler(routerFunction, defaultStrategies());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given {@linkplain RouterFunction routing function} into a {@link HttpHandler},
|
||||
* using the given configuration.
|
||||
* using the given strategies.
|
||||
*
|
||||
* <p>The returned {@code HttpHandler} can be adapted to run in
|
||||
* <ul>
|
||||
@@ -141,26 +141,26 @@ public abstract class RouterFunctions {
|
||||
* </ul>
|
||||
*
|
||||
* @param routerFunction the routing function to convert
|
||||
* @param configuration the configuration to use
|
||||
* @param strategies the strategies to use
|
||||
* @return an http handler that handles HTTP request using the given routing function
|
||||
*/
|
||||
public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction, Configuration configuration) {
|
||||
public static HttpHandler toHttpHandler(RouterFunction<?> routerFunction, StrategiesSupplier strategies) {
|
||||
Assert.notNull(routerFunction, "'routerFunction' must not be null");
|
||||
Assert.notNull(configuration, "'configuration' must not be null");
|
||||
Assert.notNull(strategies, "'strategies' must not be null");
|
||||
|
||||
return new HttpWebHandlerAdapter(exchange -> {
|
||||
Request request = new DefaultRequest(exchange, configuration);
|
||||
Request request = new DefaultRequest(exchange, strategies);
|
||||
addAttributes(exchange, request);
|
||||
|
||||
HandlerFunction<?> handlerFunction = routerFunction.route(request).orElse(notFound());
|
||||
Response<?> response = handlerFunction.handle(request);
|
||||
return response.writeTo(exchange, configuration);
|
||||
return response.writeTo(exchange, strategies);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given {@code RouterFunction} into a {@code HandlerMapping}.
|
||||
* This conversion uses the {@linkplain Configuration#builder() default configuration}.
|
||||
* This conversion uses {@linkplain StrategiesSupplier#builder() default strategies}.
|
||||
*
|
||||
* <p>The returned {@code HandlerMapping} can be run in a
|
||||
* {@link org.springframework.web.reactive.DispatcherHandler}.
|
||||
@@ -171,27 +171,28 @@ public abstract class RouterFunctions {
|
||||
* @see org.springframework.web.reactive.function.support.ResponseResultHandler
|
||||
*/
|
||||
public static HandlerMapping toHandlerMapping(RouterFunction<?> routerFunction) {
|
||||
return toHandlerMapping(routerFunction, defaultConfiguration());
|
||||
return toHandlerMapping(routerFunction, defaultStrategies());
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given {@linkplain RouterFunction routing function} into a {@link HandlerMapping}
|
||||
* using the given configuration.
|
||||
* Converts the given {@linkplain RouterFunction routing function} into a {@link HandlerMapping},
|
||||
* using the given strategies.
|
||||
*
|
||||
* <p>The returned {@code HandlerMapping} can be run in a
|
||||
* {@link org.springframework.web.reactive.DispatcherHandler}.
|
||||
*
|
||||
* @param routerFunction the routing function to convert
|
||||
* @param strategies the strategies to use
|
||||
* @return an handler mapping that maps HTTP request to a handler using the given routing function
|
||||
* @see org.springframework.web.reactive.function.support.HandlerFunctionAdapter
|
||||
* @see org.springframework.web.reactive.function.support.ResponseResultHandler
|
||||
*/
|
||||
public static HandlerMapping toHandlerMapping(RouterFunction<?> routerFunction, Configuration configuration) {
|
||||
public static HandlerMapping toHandlerMapping(RouterFunction<?> routerFunction, StrategiesSupplier strategies) {
|
||||
Assert.notNull(routerFunction, "'routerFunction' must not be null");
|
||||
Assert.notNull(configuration, "'configuration' must not be null");
|
||||
Assert.notNull(strategies, "'strategies' must not be null");
|
||||
|
||||
return exchange -> {
|
||||
Request request = new DefaultRequest(exchange, configuration);
|
||||
Request request = new DefaultRequest(exchange, strategies);
|
||||
addAttributes(exchange, request);
|
||||
|
||||
Optional<? extends HandlerFunction<?>> route = routerFunction.route(request);
|
||||
@@ -199,8 +200,8 @@ public abstract class RouterFunctions {
|
||||
};
|
||||
}
|
||||
|
||||
private static Configuration defaultConfiguration() {
|
||||
return Configuration.builder().build();
|
||||
private static StrategiesSupplier defaultStrategies() {
|
||||
return StrategiesSupplier.builder().build();
|
||||
}
|
||||
|
||||
private static void addAttributes(ServerWebExchange exchange, Request request) {
|
||||
|
||||
@@ -26,15 +26,18 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.result.view.ViewResolver;
|
||||
|
||||
/**
|
||||
* Defines the configuration to be used for processing {@link HandlerFunction}s. An instance of
|
||||
* Defines the strategies to be used for processing {@link HandlerFunction}s. An instance of
|
||||
* this class is immutable; instances are typically created through the mutable {@link Builder}:
|
||||
* either through {@link #builder()} to create a default configuration, {@link #empty()} to create
|
||||
* an empty configuration.
|
||||
* either through {@link #builder()} to set up default strategies, or {@link #empty()} to start from
|
||||
* scratch. Alternatively, {@code StrategiesSupplier} instances can be created through
|
||||
* {@link #of(Supplier, Supplier, Supplier)}.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @since 5.0
|
||||
* @see RouterFunctions#toHttpHandler(RouterFunction, StrategiesSupplier)
|
||||
* @see RouterFunctions#toHandlerMapping(RouterFunction, StrategiesSupplier)
|
||||
*/
|
||||
public interface Configuration {
|
||||
public interface StrategiesSupplier {
|
||||
|
||||
// Instance methods
|
||||
|
||||
@@ -62,19 +65,55 @@ public interface Configuration {
|
||||
// Static methods
|
||||
|
||||
/**
|
||||
* Return a mutable, empty builder for a {@code Configuration}.
|
||||
* Return a new {@code StrategiesSupplier} described by the given supplier functions. All
|
||||
* provided supplier function parameters can be {@code null} to indicate an empty stream is to
|
||||
* be returned.
|
||||
* @param messageReaders the supplier function for {@link HttpMessageReader} instances (can be {@code null})
|
||||
* @param messageWriters the supplier function for {@link HttpMessageWriter} instances (can be {@code null})
|
||||
* @param viewResolvers the supplier function for {@link ViewResolver} instances (can be {@code null})
|
||||
* @return the new {@code StrategiesSupplier}
|
||||
*/
|
||||
static StrategiesSupplier of(Supplier<Stream<HttpMessageReader<?>>> messageReaders,
|
||||
Supplier<Stream<HttpMessageWriter<?>>> messageWriters,
|
||||
Supplier<Stream<ViewResolver>> viewResolvers) {
|
||||
|
||||
return new StrategiesSupplier() {
|
||||
@Override
|
||||
public Supplier<Stream<HttpMessageReader<?>>> messageReaders() {
|
||||
return checkForNull(messageReaders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Stream<HttpMessageWriter<?>>> messageWriters() {
|
||||
return checkForNull(messageWriters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Supplier<Stream<ViewResolver>> viewResolvers() {
|
||||
return checkForNull(viewResolvers);
|
||||
}
|
||||
|
||||
private <T> Supplier<Stream<T>> checkForNull(Supplier<Stream<T>> supplier) {
|
||||
return supplier != null ? supplier : Stream::empty;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a mutable, empty builder for a {@code StrategiesSupplier}.
|
||||
* @return the builder
|
||||
*/
|
||||
static Builder empty() {
|
||||
return new DefaultConfigurationBuilder();
|
||||
return new DefaultStrategiesSupplierBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a mutable builder for a {@code Configuration} with a default initialization.
|
||||
* Return a mutable builder for a {@code StrategiesSupplier} with a default initialization.
|
||||
* @return the builder
|
||||
*/
|
||||
static Builder builder() {
|
||||
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
|
||||
DefaultStrategiesSupplierBuilder builder = new DefaultStrategiesSupplierBuilder();
|
||||
builder.defaultConfiguration();
|
||||
return builder;
|
||||
}
|
||||
@@ -83,21 +122,21 @@ public interface Configuration {
|
||||
* Return a mutable builder based on the given {@linkplain ApplicationContext application context}.
|
||||
* The returned builder will search for all {@link HttpMessageReader}, {@link HttpMessageWriter},
|
||||
* and {@link ViewResolver} instances in the given application context and return them for
|
||||
* {@link #messageReaders()}, {@link #messageWriters()}, and {@link #viewResolvers()} in the
|
||||
* built configuration respectively.
|
||||
* @param applicationContext the application context to base the configuration on
|
||||
* {@link #messageReaders()}, {@link #messageWriters()}, and {@link #viewResolvers()}
|
||||
* respectively.
|
||||
* @param applicationContext the application context to base the strategies on
|
||||
* @return the builder
|
||||
*/
|
||||
static Builder applicationContext(ApplicationContext applicationContext) {
|
||||
Assert.notNull(applicationContext, "'applicationContext' must not be null");
|
||||
DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
|
||||
DefaultStrategiesSupplierBuilder builder = new DefaultStrategiesSupplierBuilder();
|
||||
builder.applicationContext(applicationContext);
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A mutable builder for a {@link Configuration}.
|
||||
* A mutable builder for a {@link StrategiesSupplier}.
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
@@ -123,10 +162,10 @@ public interface Configuration {
|
||||
Builder viewResolver(ViewResolver viewResolver);
|
||||
|
||||
/**
|
||||
* Builds the {@link Configuration}.
|
||||
* @return the built configuration
|
||||
* Builds the {@link StrategiesSupplier}.
|
||||
* @return the built strategies
|
||||
*/
|
||||
Configuration build();
|
||||
StrategiesSupplier build();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,8 +21,8 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.HandlerResult;
|
||||
import org.springframework.web.reactive.HandlerResultHandler;
|
||||
import org.springframework.web.reactive.function.Configuration;
|
||||
import org.springframework.web.reactive.function.Response;
|
||||
import org.springframework.web.reactive.function.StrategiesSupplier;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
@@ -33,21 +33,21 @@ import org.springframework.web.server.ServerWebExchange;
|
||||
*/
|
||||
public class ResponseResultHandler implements HandlerResultHandler {
|
||||
|
||||
private final Configuration configuration;
|
||||
private final StrategiesSupplier strategies;
|
||||
|
||||
/**
|
||||
* Create a {@code ResponseResultHandler} with a default configuration.
|
||||
* Create a {@code ResponseResultHandler} with default strategies.
|
||||
*/
|
||||
public ResponseResultHandler() {
|
||||
this(Configuration.builder().build());
|
||||
this(StrategiesSupplier.builder().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@code ResponseResultHandler} with the given configuration.
|
||||
* Create a {@code ResponseResultHandler} with the given strategies.
|
||||
*/
|
||||
public ResponseResultHandler(Configuration configuration) {
|
||||
Assert.notNull(configuration, "'configuration' must not be null");
|
||||
this.configuration = configuration;
|
||||
public ResponseResultHandler(StrategiesSupplier strategies) {
|
||||
Assert.notNull(strategies, "'strategies' must not be null");
|
||||
this.strategies = strategies;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,6 +61,6 @@ public class ResponseResultHandler implements HandlerResultHandler {
|
||||
public Mono<Void> handleResult(ServerWebExchange exchange, HandlerResult result) {
|
||||
Response<?> response = (Response<?>) result.getReturnValue().orElseThrow(
|
||||
IllegalStateException::new);
|
||||
return response.writeTo(exchange, this.configuration);
|
||||
return response.writeTo(exchange, this.strategies);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,9 +48,9 @@ public class BodyExtractorsTests {
|
||||
MockServerHttpRequest request = new MockServerHttpRequest();
|
||||
request.setBody(body);
|
||||
|
||||
Configuration configuration = Configuration.builder().build();
|
||||
StrategiesSupplier strategies = StrategiesSupplier.builder().build();
|
||||
|
||||
Mono<String> result = extractor.extract(request, configuration);
|
||||
Mono<String> result = extractor.extract(request, strategies);
|
||||
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertComplete()
|
||||
@@ -69,9 +69,9 @@ public class BodyExtractorsTests {
|
||||
MockServerHttpRequest request = new MockServerHttpRequest();
|
||||
request.setBody(body);
|
||||
|
||||
Configuration configuration = Configuration.builder().build();
|
||||
StrategiesSupplier strategies = StrategiesSupplier.builder().build();
|
||||
|
||||
Flux<String> result = extractor.extract(request, configuration);
|
||||
Flux<String> result = extractor.extract(request, strategies);
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertComplete()
|
||||
.assertValues("foo");
|
||||
@@ -90,9 +90,9 @@ public class BodyExtractorsTests {
|
||||
request.getHeaders().setContentType(MediaType.APPLICATION_JSON);
|
||||
request.setBody(body);
|
||||
|
||||
Configuration configuration = Configuration.empty().build();
|
||||
StrategiesSupplier strategies = StrategiesSupplier.empty().build();
|
||||
|
||||
Flux<String> result = extractor.extract(request, configuration);
|
||||
Flux<String> result = extractor.extract(request, strategies);
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertError(UnsupportedMediaTypeStatusException.class);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ public class BodyInsertersTests {
|
||||
assertEquals(body, inserter.t());
|
||||
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
Mono<Void> result = inserter.insert(response, Configuration.builder().build());
|
||||
Mono<Void> result = inserter.insert(response, StrategiesSupplier.builder().build());
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertComplete();
|
||||
|
||||
@@ -67,7 +67,7 @@ public class BodyInsertersTests {
|
||||
assertEquals(body, inserter.t());
|
||||
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
Mono<Void> result = inserter.insert(response, Configuration.builder().build());
|
||||
Mono<Void> result = inserter.insert(response, StrategiesSupplier.builder().build());
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertComplete();
|
||||
|
||||
@@ -86,7 +86,7 @@ public class BodyInsertersTests {
|
||||
assertEquals(body, inserter.t());
|
||||
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
Mono<Void> result = inserter.insert(response, Configuration.builder().build());
|
||||
Mono<Void> result = inserter.insert(response, StrategiesSupplier.builder().build());
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertComplete();
|
||||
|
||||
@@ -111,7 +111,7 @@ public class BodyInsertersTests {
|
||||
assertEquals(body, inserter.t());
|
||||
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
Mono<Void> result = inserter.insert(response, Configuration.builder().build());
|
||||
Mono<Void> result = inserter.insert(response, StrategiesSupplier.builder().build());
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertComplete();
|
||||
|
||||
@@ -126,7 +126,7 @@ public class BodyInsertersTests {
|
||||
assertEquals(body, inserter.t());
|
||||
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
Mono<Void> result = inserter.insert(response, Configuration.builder().build());
|
||||
Mono<Void> result = inserter.insert(response, StrategiesSupplier.builder().build());
|
||||
TestSubscriber.subscribe(result)
|
||||
.assertComplete();
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DefaultRequestTests {
|
||||
|
||||
private ServerWebExchange mockExchange;
|
||||
|
||||
private Configuration mockConfiguration;
|
||||
private StrategiesSupplier mockStrategiesSupplier;
|
||||
|
||||
private DefaultRequest defaultRequest;
|
||||
|
||||
@@ -77,9 +77,9 @@ public class DefaultRequestTests {
|
||||
mockExchange = mock(ServerWebExchange.class);
|
||||
when(mockExchange.getRequest()).thenReturn(mockRequest);
|
||||
when(mockExchange.getResponse()).thenReturn(mockResponse);
|
||||
mockConfiguration = mock(Configuration.class);
|
||||
mockStrategiesSupplier = mock(StrategiesSupplier.class);
|
||||
|
||||
defaultRequest = new DefaultRequest(mockExchange, mockConfiguration);
|
||||
defaultRequest = new DefaultRequest(mockExchange, mockStrategiesSupplier);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -171,7 +171,7 @@ public class DefaultRequestTests {
|
||||
|
||||
Set<HttpMessageReader<?>> messageReaders = Collections
|
||||
.singleton(new DecoderHttpMessageReader<String>(new StringDecoder()));
|
||||
when(mockConfiguration.messageReaders()).thenReturn(messageReaders::stream);
|
||||
when(mockStrategiesSupplier.messageReaders()).thenReturn(messageReaders::stream);
|
||||
|
||||
Mono<String> resultMono = defaultRequest.body(toMono(String.class));
|
||||
assertEquals("foo", resultMono.block());
|
||||
|
||||
@@ -190,9 +190,9 @@ public class DefaultResponseBuilderTests {
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
when(exchange.getResponse()).thenReturn(response);
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
StrategiesSupplier strategies = mock(StrategiesSupplier.class);
|
||||
|
||||
result.writeTo(exchange, configuration).block();
|
||||
result.writeTo(exchange, strategies).block();
|
||||
assertEquals(201, response.getStatusCode().value());
|
||||
assertEquals("MyValue", response.getHeaders().getFirst("MyKey"));
|
||||
assertNull(response.getBody());
|
||||
@@ -207,9 +207,9 @@ public class DefaultResponseBuilderTests {
|
||||
ServerWebExchange exchange = mock(ServerWebExchange.class);
|
||||
MockServerHttpResponse response = new MockServerHttpResponse();
|
||||
when(exchange.getResponse()).thenReturn(response);
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
StrategiesSupplier strategies = mock(StrategiesSupplier.class);
|
||||
|
||||
result.writeTo(exchange, configuration).block();
|
||||
result.writeTo(exchange, strategies).block();
|
||||
assertNull(response.getBody());
|
||||
}
|
||||
|
||||
@@ -217,8 +217,8 @@ public class DefaultResponseBuilderTests {
|
||||
public void bodyInserter() throws Exception {
|
||||
String body = "foo";
|
||||
Supplier<String> supplier = () -> body;
|
||||
BiFunction<ServerHttpResponse, Configuration, Mono<Void>> writer =
|
||||
(response, configuration) -> {
|
||||
BiFunction<ServerHttpResponse, StrategiesSupplier, Mono<Void>> writer =
|
||||
(response, strategies) -> {
|
||||
byte[] bodyBytes = body.getBytes(UTF_8);
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(bodyBytes);
|
||||
DataBuffer buffer = new DefaultDataBufferFactory().wrap(byteBuffer);
|
||||
@@ -238,10 +238,10 @@ public class DefaultResponseBuilderTests {
|
||||
List<HttpMessageWriter<?>> messageWriters = new ArrayList<>();
|
||||
messageWriters.add(new EncoderHttpMessageWriter<CharSequence>(new CharSequenceEncoder()));
|
||||
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
when(configuration.messageWriters()).thenReturn(messageWriters::stream);
|
||||
StrategiesSupplier strategies = mock(StrategiesSupplier.class);
|
||||
when(strategies.messageWriters()).thenReturn(messageWriters::stream);
|
||||
|
||||
result.writeTo(exchange, configuration).block();
|
||||
result.writeTo(exchange, strategies).block();
|
||||
assertNotNull(response.getBody());
|
||||
}
|
||||
|
||||
@@ -264,7 +264,7 @@ public class DefaultResponseBuilderTests {
|
||||
List<ViewResolver> viewResolvers = new ArrayList<>();
|
||||
viewResolvers.add(viewResolver);
|
||||
|
||||
Configuration mockConfig = mock(Configuration.class);
|
||||
StrategiesSupplier mockConfig = mock(StrategiesSupplier.class);
|
||||
when(mockConfig.viewResolvers()).thenReturn(viewResolvers::stream);
|
||||
|
||||
result.writeTo(exchange, mockConfig).block();
|
||||
|
||||
@@ -120,7 +120,7 @@ public class DispatcherHandlerIntegrationTests extends AbstractHttpHandlerIntegr
|
||||
public HandlerMapping handlerMapping(RouterFunction<?> routerFunction,
|
||||
ApplicationContext applicationContext) {
|
||||
return RouterFunctions.toHandlerMapping(routerFunction,
|
||||
new org.springframework.web.reactive.function.Configuration() {
|
||||
new StrategiesSupplier() {
|
||||
@Override
|
||||
public Supplier<Stream<HttpMessageReader<?>>> messageReaders() {
|
||||
return () -> getMessageReaders().stream();
|
||||
|
||||
@@ -112,17 +112,17 @@ public class RouterFunctionsTests {
|
||||
|
||||
@Test
|
||||
public void toHttpHandler() throws Exception {
|
||||
Configuration configuration = mock(Configuration.class);
|
||||
when(configuration.messageReaders()).thenReturn(
|
||||
StrategiesSupplier strategies = mock(StrategiesSupplier.class);
|
||||
when(strategies.messageReaders()).thenReturn(
|
||||
() -> Collections.<HttpMessageReader<?>>emptyList().stream());
|
||||
when(configuration.messageWriters()).thenReturn(
|
||||
when(strategies.messageWriters()).thenReturn(
|
||||
() -> Collections.<HttpMessageWriter<?>>emptyList().stream());
|
||||
when(configuration.viewResolvers()).thenReturn(
|
||||
when(strategies.viewResolvers()).thenReturn(
|
||||
() -> Collections.<ViewResolver>emptyList().stream());
|
||||
|
||||
Request request = mock(Request.class);
|
||||
Response response = mock(Response.class);
|
||||
when(response.writeTo(any(ServerWebExchange.class), eq(configuration))).thenReturn(Mono.empty());
|
||||
when(response.writeTo(any(ServerWebExchange.class), eq(strategies))).thenReturn(Mono.empty());
|
||||
|
||||
HandlerFunction handlerFunction = mock(HandlerFunction.class);
|
||||
when(handlerFunction.handle(any(Request.class))).thenReturn(response);
|
||||
@@ -134,7 +134,7 @@ public class RouterFunctionsTests {
|
||||
when(requestPredicate.test(request)).thenReturn(false);
|
||||
|
||||
|
||||
HttpHandler result = RouterFunctions.toHttpHandler(routerFunction, configuration);
|
||||
HttpHandler result = RouterFunctions.toHttpHandler(routerFunction, strategies);
|
||||
assertNotNull(result);
|
||||
|
||||
MockServerHttpRequest httpRequest =
|
||||
|
||||
@@ -19,6 +19,9 @@ package org.springframework.web.reactive.function;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
@@ -33,12 +36,41 @@ import org.springframework.http.ReactiveHttpOutputMessage;
|
||||
import org.springframework.http.codec.HttpMessageReader;
|
||||
import org.springframework.http.codec.HttpMessageWriter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public class ConfigurationTests {
|
||||
public class StrategiesSupplierTests {
|
||||
|
||||
@Test
|
||||
public void empty() {
|
||||
StrategiesSupplier strategies = StrategiesSupplier.empty().build();
|
||||
assertEquals(Optional.empty(), strategies.messageReaders().get().findFirst());
|
||||
assertEquals(Optional.empty(), strategies.messageWriters().get().findFirst());
|
||||
assertEquals(Optional.empty(), strategies.viewResolvers().get().findFirst());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void ofSuppliers() {
|
||||
HttpMessageReader<?> messageReader = new DummyMessageReader();
|
||||
HttpMessageWriter<?> messageWriter = new DummyMessageWriter();
|
||||
|
||||
StrategiesSupplier strategies = StrategiesSupplier.of(
|
||||
() -> Stream.of(messageReader),
|
||||
() -> Stream.of(messageWriter),
|
||||
null);
|
||||
|
||||
assertEquals(1L, strategies.messageReaders().get().collect(Collectors.counting()).longValue());
|
||||
assertEquals(Optional.of(messageReader), strategies.messageReaders().get().findFirst());
|
||||
|
||||
assertEquals(1L, strategies.messageWriters().get().collect(Collectors.counting()).longValue());
|
||||
assertEquals(Optional.of(messageWriter), strategies.messageWriters().get().findFirst());
|
||||
|
||||
assertEquals(Optional.empty(), strategies.viewResolvers().get().findFirst());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toConfiguration() throws Exception {
|
||||
@@ -47,10 +79,11 @@ public class ConfigurationTests {
|
||||
applicationContext.registerSingleton("messageReader", DummyMessageReader.class);
|
||||
applicationContext.refresh();
|
||||
|
||||
Configuration configuration = Configuration.applicationContext(applicationContext).build();
|
||||
assertTrue(configuration.messageReaders().get()
|
||||
StrategiesSupplier
|
||||
strategies = StrategiesSupplier.applicationContext(applicationContext).build();
|
||||
assertTrue(strategies.messageReaders().get()
|
||||
.allMatch(r -> r instanceof DummyMessageReader));
|
||||
assertTrue(configuration.messageWriters().get()
|
||||
assertTrue(strategies.messageWriters().get()
|
||||
.allMatch(r -> r instanceof DummyMessageWriter));
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user