From 59e43269890f724f5d3284a08bade5a61ee55505 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 13 Oct 2016 16:59:33 +0200 Subject: [PATCH] Various improvements to web.reactive.function This commit introduces the following changes to web.reactive.function: - Added RouterFunction.andRoute(), a combination of RouterFunction.and() with RouterFunctions.route() - ServerRequest.pathVariable() returns String instead of Optional. An exception is thrown if the variable is not present. - Added HandlerFilterFunction.andThen and HandlerFilterFunction.apply() --- .../function/HandlerFilterFunction.java | 27 +++++++++++++++++++ .../reactive/function/RequestPredicates.java | 2 +- .../web/reactive/function/RouterFunction.java | 19 +++++++++++-- .../web/reactive/function/ServerRequest.java | 12 +++++++-- .../support/ServerRequestWrapper.java | 2 +- .../function/DefaultServerRequestTests.java | 10 ++++++- .../support/ServerRequestWrapperTests.java | 4 +-- 7 files changed, 67 insertions(+), 9 deletions(-) diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/HandlerFilterFunction.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/HandlerFilterFunction.java index cacedeb5cf..a9099e1572 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/HandlerFilterFunction.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/HandlerFilterFunction.java @@ -16,6 +16,7 @@ package org.springframework.web.reactive.function; +import org.springframework.util.Assert; import org.springframework.web.reactive.function.support.ServerRequestWrapper; /** @@ -43,4 +44,30 @@ public interface HandlerFilterFunction { */ ServerResponse filter(ServerRequest request, HandlerFunction next); + /** + * Return a composed filter function that first applies this filter, and then applies the + * {@code after} filter. + * @param after the filter to apply after this filter is applied + * @return a composed filter that first applies this function and then applies the + * {@code after} function + */ + default HandlerFilterFunction andThen(HandlerFilterFunction after) { + Assert.notNull(after, "'after' must not be null"); + return (request, next) -> { + HandlerFunction nextHandler = + handlerRequest -> after.filter(handlerRequest, next); + return filter(request, nextHandler); + }; + } + + /** + * Apply this filter to the given handler function, resulting in a filtered handler function. + * @param handler the handler function to filter + * @return the filtered handler function + */ + default HandlerFunction apply(HandlerFunction handler) { + Assert.notNull(handler, "'handler' must not be null"); + return request -> this.filter(request, handler); + } + } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RequestPredicates.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RequestPredicates.java index b66e6f46c5..b3d374331d 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RequestPredicates.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RequestPredicates.java @@ -336,7 +336,7 @@ public abstract class RequestPredicates { } @Override - public Optional pathVariable(String name) { + public String pathVariable(String name) { return this.request.pathVariable(name); } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RouterFunction.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RouterFunction.java index 04d24c2db0..b0aa3b28b1 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RouterFunction.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/RouterFunction.java @@ -71,6 +71,22 @@ public interface RouterFunction { }; } + /** + * Return a composed routing function that first invokes this function, + * and then routes to the given handler function if the given request predicate applies. This + * method is a convenient combination of {@link #and(RouterFunction)} and + * {@link RouterFunctions#route(RequestPredicate, HandlerFunction)}. + * @param predicate the predicate to test + * @param handlerFunction the handler function to route to + * @return a composed function that first routes with this function and then the function + * created from {@code predicate} and {@code handlerFunction} if this + * function has no result + */ + default RouterFunction andRoute(RequestPredicate predicate, + HandlerFunction handlerFunction) { + return and(RouterFunctions.route(predicate, handlerFunction)); + } + /** * Filter all {@linkplain HandlerFunction handler functions} routed by this function with the given * {@linkplain HandlerFilterFunction filter function}. @@ -80,8 +96,7 @@ public interface RouterFunction { * @return the filtered routing function */ default RouterFunction filter(HandlerFilterFunction filterFunction) { - return request -> this.route(request) - .map(handlerFunction -> filterRequest -> filterFunction.filter(filterRequest, handlerFunction)); + return request -> this.route(request).map(filterFunction::apply); } } diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerRequest.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerRequest.java index 7d73cce3df..d9ce3511c2 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerRequest.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/ServerRequest.java @@ -101,9 +101,17 @@ public interface ServerRequest { * Return the path variable with the given name, if present. * @param name the variable name * @return the variable value + * @throws IllegalArgumentException if there is no path variable with the given name */ - default Optional pathVariable(String name) { - return Optional.ofNullable(this.pathVariables().get(name)); + default String pathVariable(String name) { + Map pathVariables = pathVariables(); + if (pathVariables.containsKey(name)) { + return pathVariables().get(name); + } + else { + throw new IllegalArgumentException( + "No path variable with name \"" + name + "\" available"); + } } /** diff --git a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ServerRequestWrapper.java b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ServerRequestWrapper.java index 7cf5dec215..e1420284a1 100644 --- a/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ServerRequestWrapper.java +++ b/spring-web-reactive/src/main/java/org/springframework/web/reactive/function/support/ServerRequestWrapper.java @@ -104,7 +104,7 @@ public class ServerRequestWrapper implements ServerRequest { } @Override - public Optional pathVariable(String name) { + public String pathVariable(String name) { return this.request.pathVariable(name); } diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultServerRequestTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultServerRequestTests.java index fb656606d2..5a5e855e69 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultServerRequestTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/DefaultServerRequestTests.java @@ -119,7 +119,15 @@ public class DefaultServerRequestTests { Map pathVariables = Collections.singletonMap("foo", "bar"); when(mockExchange.getAttribute(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE)).thenReturn(Optional.of(pathVariables)); - assertEquals(Optional.of("bar"), defaultRequest.pathVariable("foo")); + assertEquals("bar", defaultRequest.pathVariable("foo")); + } + + @Test(expected = IllegalArgumentException.class) + public void pathVariableNotFound() throws Exception { + Map pathVariables = Collections.singletonMap("foo", "bar"); + when(mockExchange.getAttribute(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE)).thenReturn(Optional.of(pathVariables)); + + assertEquals("bar", defaultRequest.pathVariable("baz")); } @Test diff --git a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/support/ServerRequestWrapperTests.java b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/support/ServerRequestWrapperTests.java index c619b48491..ad4897667e 100644 --- a/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/support/ServerRequestWrapperTests.java +++ b/spring-web-reactive/src/test/java/org/springframework/web/reactive/function/support/ServerRequestWrapperTests.java @@ -116,9 +116,9 @@ public class ServerRequestWrapperTests { public void pathVariable() throws Exception { String name = "foo"; String value = "bar"; - when(mockRequest.pathVariable(name)).thenReturn(Optional.of(value)); + when(mockRequest.pathVariable(name)).thenReturn(value); - assertEquals(Optional.of(value), wrapper.pathVariable(name)); + assertEquals(value, wrapper.pathVariable(name)); } @Test -- GitLab