From fb8bbe838d3a4a3657dd90928f4320d092c25db3 Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Wed, 12 Nov 2025 10:52:04 +0000 Subject: [PATCH] Polishing in RouterFunctions See gh-35791 --- .../server/RouterFunctionBuilder.java | 243 ++--- .../function/server/RouterFunctions.java | 851 ++++++++++-------- .../function/RouterFunctionBuilder.java | 215 ++--- .../web/servlet/function/RouterFunctions.java | 781 ++++++++-------- 4 files changed, 1130 insertions(+), 960 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctionBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctionBuilder.java index 8a68b92c2e8..e704adbbf88 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctionBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctionBuilder.java @@ -40,6 +40,7 @@ import org.springframework.util.Assert; * * @author Arjen Poutsma * @author Sebastien Deleuze + * @author Rossen Stoyanchev * @since 5.1 */ class RouterFunctionBuilder implements RouterFunctions.Builder { @@ -59,184 +60,201 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { return this; } - private RouterFunctions.Builder add(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RouterFunctions.route(predicate, handlerFunction)); + private RouterFunctions.Builder add( + RequestPredicate predicate, HandlerFunction function) { + + return add(RouterFunctions.route(predicate, function)); } // GET @Override - public RouterFunctions.Builder GET(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.GET), handlerFunction); + public RouterFunctions.Builder GET(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.GET), function); } @Override - public RouterFunctions.Builder GET(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.GET).and(predicate), handlerFunction); + public RouterFunctions.Builder GET( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.GET).and(predicate), function); } @Override - public RouterFunctions.Builder GET(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.GET(pattern), handlerFunction); + public RouterFunctions.Builder GET(String pattern, HandlerFunction function) { + return add(RequestPredicates.GET(pattern), function); } @Override - public RouterFunctions.Builder GET(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder GET( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.GET(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.GET(pattern).and(predicate), function); } // HEAD @Override - public RouterFunctions.Builder HEAD(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.HEAD), handlerFunction); + public RouterFunctions.Builder HEAD(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.HEAD), function); } @Override - public RouterFunctions.Builder HEAD(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.HEAD).and(predicate), handlerFunction); + public RouterFunctions.Builder HEAD( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.HEAD).and(predicate), function); } @Override - public RouterFunctions.Builder HEAD(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.HEAD(pattern), handlerFunction); + public RouterFunctions.Builder HEAD(String pattern, HandlerFunction function) { + return add(RequestPredicates.HEAD(pattern), function); } @Override - public RouterFunctions.Builder HEAD(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder HEAD( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.HEAD(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.HEAD(pattern).and(predicate), function); } // POST @Override - public RouterFunctions.Builder POST(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.POST), handlerFunction); + public RouterFunctions.Builder POST(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.POST), function); } @Override - public RouterFunctions.Builder POST(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.POST).and(predicate), handlerFunction); + public RouterFunctions.Builder POST( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.POST).and(predicate), function); } @Override - public RouterFunctions.Builder POST(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.POST(pattern), handlerFunction); + public RouterFunctions.Builder POST(String pattern, HandlerFunction function) { + return add(RequestPredicates.POST(pattern), function); } @Override - public RouterFunctions.Builder POST(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder POST( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.POST(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.POST(pattern).and(predicate), function); } // PUT @Override - public RouterFunctions.Builder PUT(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PUT), handlerFunction); + public RouterFunctions.Builder PUT(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.PUT), function); } @Override - public RouterFunctions.Builder PUT(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PUT).and(predicate), handlerFunction); + public RouterFunctions.Builder PUT( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.PUT).and(predicate), function); } @Override - public RouterFunctions.Builder PUT(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.PUT(pattern), handlerFunction); + public RouterFunctions.Builder PUT(String pattern, HandlerFunction function) { + return add(RequestPredicates.PUT(pattern), function); } @Override - public RouterFunctions.Builder PUT(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder PUT( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.PUT(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.PUT(pattern).and(predicate), function); } // PATCH @Override - public RouterFunctions.Builder PATCH(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PATCH), handlerFunction); + public RouterFunctions.Builder PATCH(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.PATCH), function); } @Override - public RouterFunctions.Builder PATCH(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PATCH).and(predicate), handlerFunction); + public RouterFunctions.Builder PATCH( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.PATCH).and(predicate), function); } @Override - public RouterFunctions.Builder PATCH(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.PATCH(pattern), handlerFunction); + public RouterFunctions.Builder PATCH(String pattern, HandlerFunction function) { + return add(RequestPredicates.PATCH(pattern), function); } @Override - public RouterFunctions.Builder PATCH(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder PATCH( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.PATCH(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.PATCH(pattern).and(predicate), function); } // DELETE @Override - public RouterFunctions.Builder DELETE(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.DELETE), handlerFunction); + public RouterFunctions.Builder DELETE(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.DELETE), function); } @Override - public RouterFunctions.Builder DELETE(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.DELETE).and(predicate), handlerFunction); + public RouterFunctions.Builder DELETE( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.DELETE).and(predicate), function); } @Override - public RouterFunctions.Builder DELETE(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.DELETE(pattern), handlerFunction); + public RouterFunctions.Builder DELETE(String pattern, HandlerFunction function) { + return add(RequestPredicates.DELETE(pattern), function); } @Override - public RouterFunctions.Builder DELETE(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder DELETE( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.DELETE(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.DELETE(pattern).and(predicate), function); } // OPTIONS @Override - public RouterFunctions.Builder OPTIONS(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.OPTIONS), handlerFunction); + public RouterFunctions.Builder OPTIONS(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.OPTIONS), function); } @Override - public RouterFunctions.Builder OPTIONS(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.OPTIONS).and(predicate), handlerFunction); + public RouterFunctions.Builder OPTIONS( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.OPTIONS).and(predicate), function); } @Override - public RouterFunctions.Builder OPTIONS(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.OPTIONS(pattern), handlerFunction); + public RouterFunctions.Builder OPTIONS(String pattern, HandlerFunction function) { + return add(RequestPredicates.OPTIONS(pattern), function); } @Override - public RouterFunctions.Builder OPTIONS(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder OPTIONS( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.OPTIONS(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.OPTIONS(pattern).and(predicate), function); } // other @Override - public RouterFunctions.Builder route(RequestPredicate predicate, - HandlerFunction handlerFunction) { - return add(RouterFunctions.route(predicate, handlerFunction)); + public RouterFunctions.Builder route( + RequestPredicate predicate, HandlerFunction function) { + + return add(RouterFunctions.route(predicate, function)); } @Override @@ -245,8 +263,10 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder resource(RequestPredicate predicate, Resource resource, + public RouterFunctions.Builder resource( + RequestPredicate predicate, Resource resource, BiConsumer headersConsumer) { + return add(RouterFunctions.resource(predicate, resource, headersConsumer)); } @@ -256,8 +276,8 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder resources(String pattern, Resource location, - BiConsumer headersConsumer) { + public RouterFunctions.Builder resources( + String pattern, Resource location, BiConsumer headersConsumer) { return add(RouterFunctions.resources(pattern, location, headersConsumer)); } @@ -268,15 +288,16 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder resources(Function> lookupFunction, + public RouterFunctions.Builder resources( + Function> lookupFunction, BiConsumer headersConsumer) { return add(RouterFunctions.resources(lookupFunction, headersConsumer)); } @Override - public RouterFunctions.Builder nest(RequestPredicate predicate, - Consumer builderConsumer) { + public RouterFunctions.Builder nest( + RequestPredicate predicate, Consumer builderConsumer) { Assert.notNull(builderConsumer, "Consumer must not be null"); @@ -289,26 +310,26 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { @SuppressWarnings("unchecked") @Override - public RouterFunctions.Builder nest(RequestPredicate predicate, - Supplier> routerFunctionSupplier) { + public RouterFunctions.Builder nest( + RequestPredicate predicate, Supplier> routerFunctionSupplier) { Assert.notNull(routerFunctionSupplier, "RouterFunction Supplier must not be null"); - RouterFunction nestedRoute = (RouterFunction) routerFunctionSupplier.get(); - this.routerFunctions.add(RouterFunctions.nest(predicate, nestedRoute)); + RouterFunction route = (RouterFunction) routerFunctionSupplier.get(); + this.routerFunctions.add(RouterFunctions.nest(predicate, route)); return this; } @Override - public RouterFunctions.Builder path(String pattern, - Consumer builderConsumer) { + public RouterFunctions.Builder path( + String pattern, Consumer builderConsumer) { return nest(RequestPredicates.path(pattern), builderConsumer); } @Override - public RouterFunctions.Builder path(String pattern, - Supplier> routerFunctionSupplier) { + public RouterFunctions.Builder path( + String pattern, Supplier> routerFunctionSupplier) { return nest(RequestPredicates.path(pattern), routerFunctionSupplier); } @@ -319,7 +340,6 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { HandlerFilterFunction filterFunction) { Assert.notNull(filterFunction, "HandlerFilterFunction must not be null"); - this.filterFunctions.add((HandlerFilterFunction) filterFunction); return this; } @@ -341,14 +361,16 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder onError(Predicate predicate, + public RouterFunctions.Builder onError( + Predicate predicate, BiFunction> responseProvider) { Assert.notNull(predicate, "Predicate must not be null"); Assert.notNull(responseProvider, "ResponseProvider must not be null"); - this.errorHandlers.add(0, (request, next) -> next.handle(request) - .onErrorResume(predicate, t -> responseProvider.apply(t, request))); + this.errorHandlers.add(0, (request, next) -> + next.handle(request).onErrorResume(predicate, t -> responseProvider.apply(t, request))); + return this; } @@ -359,8 +381,9 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { Assert.notNull(exceptionType, "ExceptionType must not be null"); Assert.notNull(responseProvider, "ResponseProvider must not be null"); - this.errorHandlers.add(0, (request, next) -> next.handle(request) - .onErrorResume(exceptionType, t -> responseProvider.apply(t, request))); + this.errorHandlers.add(0, (request, next) -> + next.handle(request).onErrorResume(exceptionType, t -> responseProvider.apply(t, request))); + return this; } @@ -368,54 +391,46 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { public RouterFunctions.Builder withAttribute(String name, Object value) { Assert.hasLength(name, "Name must not be empty"); Assert.notNull(value, "Value must not be null"); - - if (this.routerFunctions.isEmpty()) { - throw new IllegalStateException("attributes can only be called after any other method (GET, path, etc.)"); - } + Assert.state(!this.routerFunctions.isEmpty(), + "attributes can only be called after any other method (GET, path, etc.)"); int lastIdx = this.routerFunctions.size() - 1; - RouterFunction attributed = this.routerFunctions.get(lastIdx) - .withAttribute(name, value); + RouterFunction attributed = this.routerFunctions.get(lastIdx).withAttribute(name, value); this.routerFunctions.set(lastIdx, attributed); return this; } @Override - public RouterFunctions.Builder withAttributes(Consumer> attributesConsumer) { - Assert.notNull(attributesConsumer, "AttributesConsumer must not be null"); - - if (this.routerFunctions.isEmpty()) { - throw new IllegalStateException("attributes can only be called after any other method (GET, path, etc.)"); - } + public RouterFunctions.Builder withAttributes(Consumer> consumer) { + Assert.notNull(consumer, "AttributesConsumer must not be null"); + Assert.state(!this.routerFunctions.isEmpty(), + "attributes can only be called after any other method (GET, path, etc.)"); int lastIdx = this.routerFunctions.size() - 1; - RouterFunction attributed = this.routerFunctions.get(lastIdx) - .withAttributes(attributesConsumer); + RouterFunction attributed = this.routerFunctions.get(lastIdx).withAttributes(consumer); this.routerFunctions.set(lastIdx, attributed); return this; } @Override public RouterFunction build() { - if (this.routerFunctions.isEmpty()) { - throw new IllegalStateException("No routes registered. Register a route with GET(), POST(), etc."); - } - RouterFunction result = new BuiltRouterFunction(this.routerFunctions); + Assert.state(!this.routerFunctions.isEmpty(), + "No routes registered. Register a route with GET(), POST(), etc."); + RouterFunction result = new BuiltRouterFunction(this.routerFunctions); if (this.filterFunctions.isEmpty() && this.errorHandlers.isEmpty()) { return result; } - else { - HandlerFilterFunction filter = - Stream.concat(this.filterFunctions.stream(), this.errorHandlers.stream()) - .reduce(HandlerFilterFunction::andThen) - .orElseThrow(IllegalStateException::new); + HandlerFilterFunction filter = + Stream.concat(this.filterFunctions.stream(), this.errorHandlers.stream()) + .reduce(HandlerFilterFunction::andThen) + .orElseThrow(IllegalStateException::new); - return result.filter(filter); - } + return result.filter(filter); } /** - * Router function returned by {@link #build()} that simply iterates over the registered routes. + * Router function returned by {@link #build()} that simply iterates over + * the registered routes. */ private static class BuiltRouterFunction extends RouterFunctions.AbstractRouterFunction { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java index 7e01122cdb1..e1d469a6419 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java @@ -46,20 +46,21 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder; import org.springframework.web.util.pattern.PathPatternParser; /** - * Central entry point to Spring's functional web framework. + * Central entry point to Spring's functional WebFlux framework. * Exposes routing functionality, such as to {@linkplain #route() create} a * {@code RouterFunction} using a discoverable builder-style API, to - * {@linkplain #route(RequestPredicate, HandlerFunction) create} a {@code RouterFunction} - * given a {@code RequestPredicate} and {@code HandlerFunction}, and to do further - * {@linkplain #nest(RequestPredicate, RouterFunction) subrouting} on an existing routing - * function. + * {@linkplain #route(RequestPredicate, HandlerFunction) create} a + * {@code RouterFunction} given a {@code RequestPredicate} and + * {@code HandlerFunction}, and to do further + * {@linkplain #nest(RequestPredicate, RouterFunction) subrouting} on an + * existing routing function. * - *

Additionally, this class can {@linkplain #toHttpHandler(RouterFunction) transform} - * a {@code RouterFunction} into an {@code HttpHandler}, which can be run in Servlet - * environments, or Reactor. + *

Use {@linkplain #toHttpHandler(RouterFunction)} to turn a + * {@code RouterFunction} into a WebFlux {@code HttpHandler}. * * @author Arjen Poutsma * @author Sebastien Deleuze + * @author Rossen Stoyanchev * @since 5.0 */ public abstract class RouterFunctions { @@ -86,10 +87,9 @@ public abstract class RouterFunctions { RouterFunctions.class.getName() + ".matchingPattern"; - - /** - * Offers a discoverable way to create router functions through a builder-style interface. + * Offers a discoverable way to create router functions through + * a WebFlux builder-style interface. * @return a router function builder * @since 5.1 */ @@ -99,8 +99,8 @@ public abstract class RouterFunctions { /** * Route to the given handler function if the given request predicate applies. - *

For instance, the following example routes GET requests for "/user" to the - * {@code listUsers} method in {@code userController}: + *

For instance, the following example routes GET requests for "/user" + * to the {@code listUsers} method in {@code userController}: *

 	 * RouterFunction<ServerResponse> route =
 	 *     RouterFunctions.route(RequestPredicates.GET("/user"), userController::listUsers);
@@ -119,22 +119,24 @@ public abstract class RouterFunctions {
 	}
 
 	/**
-	 * Route to the given router function if the given request predicate applies. This method can be
-	 * used to create nested routes, where a group of routes share a common path
-	 * (prefix), header, or other request predicate.
-	 * 

For instance, the following example first creates a composed route that resolves to - * {@code listUsers} for a GET, and {@code createUser} for a POST. This composed route then gets - * nested with a "/user" path predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * Route to the given router function if the given request predicate applies. + * Use method to create nested routes, where a group of + * routes share a common path (prefix), header, or other request predicate. + *

For instance, the following example first creates a composed route + * that resolves to {@code listUsers} for a GET, and {@code createUser} + * for a POST. This composed route then gets nested with a "/user" path + * predicate, so that GET requests for "/user" will list users, and POST + * request for "/user" will create a new user: *

 	 * RouterFunction<ServerResponse> userRoutes =
-	 *   RouterFunctions.route(RequestPredicates.method(HttpMethod.GET), this::listUsers)
-	 *     .andRoute(RequestPredicates.method(HttpMethod.POST), this::createUser);
+	 *     RouterFunctions.route(RequestPredicates.method(HttpMethod.GET), this::listUsers)
+	 *         .andRoute(RequestPredicates.method(HttpMethod.POST), this::createUser);
+	 *
 	 * RouterFunction<ServerResponse> nestedRoute =
-	 *   RouterFunctions.nest(RequestPredicates.path("/user"), userRoutes);
+	 *       RouterFunctions.nest(RequestPredicates.path("/user"), userRoutes);
 	 * 
* @param predicate the predicate to test - * @param routerFunction the nested router function to delegate to if the predicate applies + * @param routerFunction the nested router function * @param the type of response returned by the handler function * @return a router function that routes to {@code routerFunction} if * {@code predicate} evaluates to {@code true} @@ -148,7 +150,7 @@ public abstract class RouterFunctions { /** * Route requests that match the given predicate to the given resource. - * For instance + * For instance: *
 	 * Resource resource = new ClassPathResource("static/index.html")
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resource(path("/api/**").negate(), resource);
@@ -159,30 +161,34 @@ public abstract class RouterFunctions {
 	 * @since 6.1.4
 	 */
 	public static RouterFunction resource(RequestPredicate predicate, Resource resource) {
-		return resources(new PredicateResourceLookupFunction(predicate, resource), (consumerResource, httpHeaders) -> {});
+		PredicateResourceLookupFunction function = new PredicateResourceLookupFunction(predicate, resource);
+		return resources(function, (consumerResource, httpHeaders) -> {});
 	}
 
 	/**
 	 * Route requests that match the given predicate to the given resource.
-	 * For instance
+	 * For instance:
 	 * 
 	 * Resource resource = new ClassPathResource("static/index.html")
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resource(path("/api/**").negate(), resource);
 	 * 
* @param predicate the predicate to match * @param resource the resources to serve - * @param headersConsumer provides access to the HTTP headers for served resources + * @param headersConsumer for access to the HTTP headers for served resources * @return a router function that routes to a resource * @since 6.1.4 */ - public static RouterFunction resource(RequestPredicate predicate, Resource resource, + public static RouterFunction resource( + RequestPredicate predicate, Resource resource, BiConsumer headersConsumer) { - return resources(new PredicateResourceLookupFunction(predicate, resource), headersConsumer); + + PredicateResourceLookupFunction function = new PredicateResourceLookupFunction(predicate, resource); + return resources(function, headersConsumer); } /** - * Route requests that match the given pattern to resources relative to the given root location. - * For instance + * Route requests that match the given pattern to resources relative to the + * given root location. For instance: *
 	 * Resource location = new FileUrlResource("public-resources/");
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -198,8 +204,8 @@ public abstract class RouterFunctions {
 	}
 
 	/**
-	 * Route requests that match the given pattern to resources relative to the given root location.
-	 * For instance
+	 * Route requests that match the given pattern to resources relative to the
+	 * given root location. For instance:
 	 * 
 	 * Resource location = new FileUrlResource("public-resources/");
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -212,20 +218,23 @@ public abstract class RouterFunctions {
 	 * @see org.springframework.web.util.pattern.PathPattern
 	 * @see #resourceLookupFunction(String, Resource)
 	 */
-	public static RouterFunction resources(String pattern, Resource location,
+	public static RouterFunction resources(
+			String pattern, Resource location,
 			BiConsumer headersConsumer) {
+
 		return resources(resourceLookupFunction(pattern, location), headersConsumer);
 	}
 
 	/**
-	 * Returns the resource lookup function used by {@link #resources(String, Resource)}.
-	 * The returned function can be {@linkplain Function#andThen(Function) composed} on, for
-	 * instance to return a default resource when the lookup function does not match:
+	 * Returns the resource lookup function used by
+	 * {@link #resources(String, Resource)}. The returned function can be
+	 * {@linkplain Function#andThen(Function) composed} on. For instance to
+	 * return a default resource when the lookup function does not match:
 	 * 
 	 * Mono<Resource> defaultResource = Mono.just(new ClassPathResource("index.html"));
 	 * Function<ServerRequest, Mono<Resource>> lookupFunction =
-	 *   RouterFunctions.resourceLookupFunction("/resources/**", new FileUrlResource("public-resources/"))
-	 *     .andThen(resourceMono -> resourceMono.switchIfEmpty(defaultResource));
+	 *     RouterFunctions.resourceLookupFunction("/resources/**", new FileUrlResource("public-resources/"))
+	 *         .andThen(resourceMono -> resourceMono.switchIfEmpty(defaultResource));
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resources(lookupFunction);
      * 
* @param pattern the pattern to match @@ -233,32 +242,40 @@ public abstract class RouterFunctions { * @return the default resource lookup function for the given parameters. * @see org.springframework.web.util.pattern.PathPattern */ - public static Function> resourceLookupFunction(String pattern, Resource location) { + public static Function> resourceLookupFunction( + String pattern, Resource location) { + return new PathResourceLookupFunction(pattern, location); } /** - * Route to resources using the provided lookup function. If the lookup function provides a - * {@link Resource} for the given request, it will be it will be exposed using a - * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests. - * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest} + * Route to resources using the provided lookup function. If the lookup + * function provides a {@link Resource} for the given request, it will be + * exposed using a {@link HandlerFunction} that handles GET, HEAD, + * and OPTIONS requests. + * @param lookupFunction the function to provide a {@link Resource} * @return a router function that routes to resources */ - public static RouterFunction resources(Function> lookupFunction) { + public static RouterFunction resources( + Function> lookupFunction) { + return new ResourcesRouterFunction(lookupFunction, (resource, httpHeaders) -> {}); } /** - * Route to resources using the provided lookup function. If the lookup function provides a - * {@link Resource} for the given request, it will be it will be exposed using a - * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests. - * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest} + * Route to resources using the provided lookup function. If the lookup + * function provides a {@link Resource} for the given request, it will be + * exposed using a {@link HandlerFunction} that handles GET, HEAD, + * and OPTIONS requests. + * @param lookupFunction the function to provide a {@link Resource} * @param headersConsumer provides access to the HTTP headers for served resources * @return a router function that routes to resources * @since 6.1 */ - public static RouterFunction resources(Function> lookupFunction, + public static RouterFunction resources( + Function> lookupFunction, BiConsumer headersConsumer) { + return new ResourcesRouterFunction(lookupFunction, headersConsumer); } @@ -266,11 +283,11 @@ public abstract class RouterFunctions { * Convert the given {@linkplain RouterFunction router function} into an * {@link HttpHandler}, using the {@linkplain HandlerStrategies#builder() * default strategies}. - *

The returned handler can be adapted to run in the following environments. + *

The returned handler can be adapted to run in the following environments: *

    - *
  • Servlet environments using the + *
  • For Servlet containers, use * {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter}
  • - *
  • Reactor using the + *
  • For Reactor Netty, use * {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter} *
*

Note that {@code HttpWebHandlerAdapter} also implements {@link WebHandler}, @@ -286,12 +303,12 @@ public abstract class RouterFunctions { /** * Convert the given {@linkplain RouterFunction router function} into an * {@link HttpHandler}, using the given strategies. - *

The returned handler can be adapted to run in the following environments. + *

The returned handler can be adapted to run in the following environments: *

    - *
  • Servlet environments using the + *
  • For Servlet containers, use * {@link org.springframework.http.server.reactive.ServletHttpHandlerAdapter}
  • - *
  • Reactor using the - * {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter}
  • + *
  • For Reactor Netty, use + * {@link org.springframework.http.server.reactive.ReactorHttpHandlerAdapter} *
* @param routerFunction the router function to convert * @param strategies the strategies to use @@ -307,8 +324,9 @@ public abstract class RouterFunctions { } /** - * Convert the given {@linkplain RouterFunction router function} into a {@link WebHandler}. - * This conversion uses {@linkplain HandlerStrategies#builder() default strategies}. + * Convert the given {@linkplain RouterFunction router function} into a + * {@link WebHandler}. This conversion uses + * {@linkplain HandlerStrategies#builder() default strategies}. * @param routerFunction the router function to convert * @return a web handler that handles web request using the given router function */ @@ -317,8 +335,8 @@ public abstract class RouterFunctions { } /** - * Convert the given {@linkplain RouterFunction router function} into a {@link WebHandler}, - * using the given strategies. + * Convert the given {@linkplain RouterFunction router function} into a + * {@link WebHandler}, using the given strategies. * @param routerFunction the router function to convert * @param strategies the strategies to use * @return a web handler that handles web request using the given router function @@ -331,16 +349,18 @@ public abstract class RouterFunctions { } /** - * Changes the {@link PathPatternParser} on the given {@linkplain RouterFunction router function}. This method - * can be used to change the {@code PathPatternParser} properties from the defaults, for instance to change - * {@linkplain PathPatternParser#setCaseSensitive(boolean) case sensitivity}. + * Changes the {@link PathPatternParser} on the given + * {@linkplain RouterFunction router function}. This method can be used to + * change the {@code PathPatternParser} properties from the defaults. + * For instance to change {@linkplain PathPatternParser#setCaseSensitive(boolean) + * case sensitivity}. * @param routerFunction the router function to change the parser in * @param parser the parser to change to. * @param the type of response returned by the handler function * @return the change router function */ - public static RouterFunction changeParser(RouterFunction routerFunction, - PathPatternParser parser) { + public static RouterFunction changeParser( + RouterFunction routerFunction, PathPatternParser parser) { Assert.notNull(routerFunction, "RouterFunction must not be null"); Assert.notNull(parser, "Parser must not be null"); @@ -359,366 +379,398 @@ public abstract class RouterFunctions { public interface Builder { /** - * Adds a route to the given handler function that handles HTTP {@code GET} requests. - * @param handlerFunction the handler function to handle all {@code GET} requests + * Adds a route to the given handler function that handles + * HTTP {@code GET} requests. + * @param handlerFunction handler for GET requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder GET(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code GET} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code GET} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code GET} requests that - * match {@code pattern} + * @param handlerFunction handler for GET requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder GET(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code GET} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code GET} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code GET} requests that - * match {@code predicate} + * @param handlerFunction handler for GET requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder GET(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder GET( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code GET} requests - * that match the given pattern and predicate. - *

For instance, the following example routes GET requests for "/user" that accept JSON - * to the {@code listUsers} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code GET} requests that match the given pattern and predicate. + *

For instance, the below routes GET requests for "/user" that + * accept JSON to the {@code listUsers} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userController::listUsers)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userController::listUsers)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code GET} requests that - * match {@code pattern} and the predicate + * @param handlerFunction handler for GET requests that match {@code pattern} and the predicate + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern * @see RequestPredicates */ - Builder GET(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder GET( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** * Adds a route to the given handler function that handles HTTP {@code HEAD} requests. - * @param handlerFunction the handler function to handle all {@code HEAD} requests + * @param handlerFunction handler for HEAD requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder HEAD(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code HEAD} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code HEAD} requests that - * match {@code pattern} + * @param handlerFunction handler for HEAD requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder HEAD(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code HEAD} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code HEAD} requests that - * match {@code predicate} + * @param handlerFunction handler for HEAD requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder HEAD(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder HEAD( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests - * that match the given pattern and predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code HEAD} requests that match the given pattern and predicate. * @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code HEAD} requests that - * match {@code pattern} + * @param handlerFunction handler for HEAD requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder HEAD(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder HEAD( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code POST} requests. - * @param handlerFunction the handler function to handle all {@code POST} requests + * Adds a route to the given handler function that handles + * HTTP {@code POST} requests. + * @param handlerFunction handler for POST requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder POST(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code POST} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code POST} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code POST} requests that - * match {@code pattern} + * @param handlerFunction handler for POST requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder POST(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code POST} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code POST} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code POST} requests that - * match {@code predicate} + * @param handlerFunction handler for POST requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder POST(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder POST( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code POST} requests - * that match the given pattern and predicate. - *

For instance, the following example routes POST requests for "/user" that contain JSON - * to the {@code addUser} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code POST} requests that match the given pattern and predicate. + *

For instance, the below routes POST requests for "/user" that + * contain JSON to the {@code addUser} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .POST("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::addUser)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .POST("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::addUser)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code POST} requests that - * match {@code pattern} + * @param handlerFunction handler for POST requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder POST(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder POST( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code PUT} requests. - * @param handlerFunction the handler function to handle all {@code PUT} requests + * Adds a route to the given handler function that handles + * HTTP {@code PUT} requests. + * @param handlerFunction handler for PUT requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder PUT(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PUT} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code PUT} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code PUT} requests that - * match {@code pattern} + * @param handlerFunction handler for PUT requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder PUT(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PUT} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code PUT} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code PUT} requests that - * match {@code predicate} + * @param handlerFunction handler for PUT requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder PUT(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PUT( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PUT} requests - * that match the given pattern and predicate. - *

For instance, the following example routes PUT requests for "/user" that contain JSON - * to the {@code editUser} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code PUT} requests that match the given pattern and predicate. + *

For instance, the below routes PUT requests for "/user" that + * contain JSON to the {@code editUser} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .PUT("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .PUT("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code PUT} requests that - * match {@code pattern} + * @param handlerFunction handler for PUT requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder PUT(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PUT( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code PATCH} requests. - * @param handlerFunction the handler function to handle all {@code PATCH} requests + * Adds a route to the given handler function that handles + * HTTP {@code PATCH} requests. + * @param handlerFunction handler for PATCH requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder PATCH(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code PATCH} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code PATCH} requests that - * match {@code pattern} + * @param handlerFunction handler for PATCH requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder PATCH(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code PATCH} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code PATCH} requests that - * match {@code predicate} + * @param handlerFunction handler for PATCH requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder PATCH(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PATCH( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests - * that match the given pattern and predicate. - *

For instance, the following example routes PATCH requests for "/user" that contain JSON - * to the {@code editUser} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code PATCH} requests that match the given pattern and predicate. + *

For instance, the below routes PATCH requests for "/user" that + * contain JSON to the {@code editUser} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .PATCH("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .PATCH("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code PATCH} requests that - * match {@code pattern} + * @param handlerFunction handler for PATCH requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder PATCH(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PATCH( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code DELETE} requests. - * @param handlerFunction the handler function to handle all {@code DELETE} requests + * Adds a route to the given handler function that handles + * HTTP {@code DELETE} requests. + * @param handlerFunction handler for DELETE requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder DELETE(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code DELETE} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code DELETE} requests that - * match {@code pattern} + * @param handlerFunction handler for DELETE requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder DELETE(String pattern, HandlerFunction handlerFunction); + Builder DELETE( + String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code DELETE} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code DELETE} requests that - * match {@code predicate} + * @param handlerFunction handler for DELETE requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder DELETE(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder DELETE( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests - * that match the given pattern and predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code DELETE} requests that match the given pattern and predicate. * @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code DELETE} requests that - * match {@code pattern} + * @param handlerFunction handler for DELETE requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder DELETE(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder DELETE( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code OPTIONS} requests. - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests + * Adds a route to the given handler function that handles + * HTTP {@code OPTIONS} requests. + * @param handlerFunction handler for OPTIONS requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder OPTIONS(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code OPTIONS} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that - * match {@code pattern} + * @param handlerFunction handler for OPTIONS requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder OPTIONS(String pattern, HandlerFunction handlerFunction); + Builder OPTIONS( + String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code OPTIONS} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that - * match {@code predicate} + * @param handlerFunction handler for OPTIONS requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder OPTIONS(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder OPTIONS( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests - * that match the given pattern and predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code OPTIONS} requests that match the given pattern and predicate. * @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that - * match {@code pattern} + * @param handlerFunction handler for OPTIONS requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder OPTIONS(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder OPTIONS( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all requests that match the - * given predicate. + * Adds a route to the given handler function that handles all + * requests that match the given predicate. * @param predicate the request predicate to match - * @param handlerFunction the handler function to handle all requests that match the predicate + * @param handlerFunction handler for requests that match the predicate + * @param the type of response returned by the handler function * @return this builder * @since 5.2 * @see RequestPredicates */ - Builder route(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder route( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds the given route to this builder. Can be used to merge externally defined router - * functions into this builder, or can be combined with + * Adds the given route to this builder. Can be used to merge externally + * defined router functions into this builder, or can be combined with * {@link RouterFunctions#route(RequestPredicate, HandlerFunction)} * to allow for more flexible predicate matching. - *

For instance, the following example adds the router function returned from - * {@code OrderController.routerFunction()}. - * to the {@code changeUser} method in {@code userController}: + *

For instance, the fbelow adds the router function returned from + * {@code OrderController.routerFunction()} to the {@code changeUser} + * method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .GET("/users", userController::listUsers)
-		 *     .add(orderController.routerFunction());
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/users", userController::listUsers)
+		 *         .add(orderController.routerFunction());
+		 *         .build();
 		 * 
* @param routerFunction the router function to be added + * @param the type of response returned by the handler function * @return this builder * @see RequestPredicates */ @@ -740,7 +792,7 @@ public abstract class RouterFunctions { /** * Route requests that match the given predicate to the given resource. - * For instance + * For instance: *
 		 * Resource resource = new ClassPathResource("static/index.html")
 		 * RouterFunction<ServerResponse> resources = RouterFunctions.resource(path("/api/**").negate(), resource);
@@ -751,11 +803,13 @@ public abstract class RouterFunctions {
 		 * @return a router function that routes to a resource
 		 * @since 6.1.4
 		 */
-		Builder resource(RequestPredicate predicate, Resource resource, BiConsumer headersConsumer);
+		Builder resource(
+				RequestPredicate predicate, Resource resource,
+				BiConsumer headersConsumer);
 
 		/**
-		 * Route requests that match the given pattern to resources relative to the given root location.
-		 * For instance
+		 * Route requests that match the given pattern to resources relative to
+		 * the given root location. For instance:
 		 * 
 		 * Resource location = new FileUrlResource("public-resources/");
 		 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -768,8 +822,8 @@ public abstract class RouterFunctions {
 		Builder resources(String pattern, Resource location);
 
 		/**
-		 * Route requests that match the given pattern to resources relative to the given root location.
-		 * For instance
+		 * Route requests that match the given pattern to resources relative to
+		 * the given root location. For instance:
 		 * 
 		 * Resource location = new FileUrlResource("public-resources/");
 		 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -781,163 +835,178 @@ public abstract class RouterFunctions {
 		 * @since 6.1
 		 * @see org.springframework.web.util.pattern.PathPattern
 		 */
-		Builder resources(String pattern, Resource location, BiConsumer headersConsumer);
+		Builder resources(
+				String pattern, Resource location,
+				BiConsumer headersConsumer);
 
 		/**
-		 * Route to resources using the provided lookup function. If the lookup function provides a
-		 * {@link Resource} for the given request, it will be it will be exposed using a
-		 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
-		 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
+		 * Route to resources using the provided lookup function.
+		 * If the lookup function provides a {@link Resource} for the given
+		 * request, it will be it will be exposed using a {@link HandlerFunction}
+		 * that handles GET, HEAD, and OPTIONS requests.
+		 * @param lookupFunction the function to provide a {@link Resource}
 		 * @return this builder
 		 */
 		Builder resources(Function> lookupFunction);
 
 		/**
-		 * Route to resources using the provided lookup function. If the lookup function provides a
-		 * {@link Resource} for the given request, it will be it will be exposed using a
-		 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
-		 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
+		 * Route to resources using the provided lookup function.
+		 * If the lookup function provides a {@link Resource} for the given
+		 * request, it will be it will be exposed using a {@link HandlerFunction}
+		 * that handles GET, HEAD, and OPTIONS requests.
+		 * @param lookupFunction the function to provide a {@link Resource}
 		 * @param headersConsumer provides access to the HTTP headers for served resources
 		 * @return this builder
 		 * @since 6.1
 		 */
-		Builder resources(Function> lookupFunction, BiConsumer headersConsumer);
+		Builder resources(
+				Function> lookupFunction,
+				BiConsumer headersConsumer);
 
 		/**
-		 * Route to the supplied router function if the given request predicate applies. This method
-		 * can be used to create nested routes, where a group of routes share a
-		 * common path (prefix), header, or other request predicate.
-		 * 

For instance, the following example creates a nested route with a "/user" path - * predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * Route to the supplied router function if the given request predicate + * applies. This method can be used to create nested routes, + * where a group of routes share a common path (prefix), header, or other + * request predicate. + *

For instance, the below creates a nested route with a "/user" path + * predicate, so that GET requests for "/user" will list users, and POST + * request for "/user" will create a new user: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .nest(RequestPredicates.path("/user"), () ->
-		 *       RouterFunctions.route()
-		 *         .GET(this::listUsers)
-		 *         .POST(this::createUser)
-		 *         .build())
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .nest(RequestPredicates.path("/user"), () ->
+		 *             RouterFunctions.route()
+		 *                 .GET(this::listUsers)
+		 *                 .POST(this::createUser)
+		 *                 .build())
+		 *         .build();
 		 * 
* @param predicate the predicate to test - * @param routerFunctionSupplier supplier for the nested router function to delegate to if - * the predicate applies + * @param routerFunctionSupplier supplier for the nested router function + * to delegate to if the predicate applies + * @param the type of response returned by the handler function * @return this builder * @see RequestPredicates */ - Builder nest(RequestPredicate predicate, Supplier> routerFunctionSupplier); + Builder nest( + RequestPredicate predicate, Supplier> routerFunctionSupplier); /** - * Route to a built router function if the given request predicate applies. - * This method can be used to create nested routes, where a group of routes - * share a common path (prefix), header, or other request predicate. - *

For instance, the following example creates a nested route with a "/user" path - * predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * Route to a built router function if the given request predicate + * applies. This method can be used to create nested routes, + * where a group of routes share a common path (prefix), header, or + * other request predicate. + *

For instance, the below creates a nested route with a "/user" path + * predicate, so that GET requests for "/user" will list users, and POST + * request for "/user" will create a new user: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .nest(RequestPredicates.path("/user"), builder ->
-		 *       builder.GET(this::listUsers)
-		 *              .POST(this::createUser))
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .nest(RequestPredicates.path("/user"), builder ->
+		 *             builder.GET(this::listUsers).POST(this::createUser))
+		 *         .build();
 		 * 
* @param predicate the predicate to test - * @param builderConsumer consumer for a {@code Builder} that provides the nested router - * function + * @param builderConsumer consumer for a {@code Builder} that provides the nested router function * @return this builder * @see RequestPredicates */ Builder nest(RequestPredicate predicate, Consumer builderConsumer); /** - * Route to the supplied router function if the given path prefix pattern applies. This method - * can be used to create nested routes, where a group of routes share a - * common path prefix. Specifically, this method can be used to merge externally defined - * router functions under a path prefix. - *

For instance, the following example creates a nested route with a "/user" path - * predicate that delegates to the router function defined in {@code userController}, - * and with a "/order" path that delegates to {@code orderController}. + * Route to the supplied router function if the given path prefix + * pattern applies. This method can be used to create + * nested routes, where a group of routes share a common + * path prefix. Specifically, this method can be used to merge + * externally defined router functions under a path prefix. + *

For instance, the below creates a nested route with a "/user" path + * predicate that delegates to the router function defined in + * {@code userController}, and with a "/order" path that delegates to + * {@code orderController}: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .path("/user", userController::routerFunction)
-		 *     .path("/order", orderController::routerFunction)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .path("/user", userController::routerFunction)
+		 *         .path("/order", orderController::routerFunction)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to - * @param routerFunctionSupplier supplier for the nested router function to delegate to if - * the pattern matches + * @param routerFunctionSupplier supplier for the nested router function + * to delegate to if the pattern matches + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder path(String pattern, Supplier> routerFunctionSupplier); + Builder path( + String pattern, Supplier> routerFunctionSupplier); /** - * Route to a built router function if the given path prefix pattern applies. - * This method can be used to create nested routes, where a group of routes - * share a common path prefix. - *

For instance, the following example creates a nested route with a "/user" path - * predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * Route to a built router function if the given path prefix pattern + * applies. This method can be used to create nested routes, + * where a group of routes share a common path prefix. + *

For instance, the following example creates a nested route with a + * "/user" path predicate, so that GET requests for "/user" will list + * users, and POST request for "/user" will create a new user: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .path("/user", builder ->
-		 *       builder.GET(this::listUsers)
-		 *              .POST(this::createUser))
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .path("/user", builder ->
+		 *             builder.GET(this::listUsers).POST(this::createUser))
+		 *         .build();
 		 * 
* @param pattern the pattern to match to - * @param builderConsumer consumer for a {@code Builder} that provides the nested router - * function + * @param builderConsumer consumer for a {@code Builder} that provides + * the nested router function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder path(String pattern, Consumer builderConsumer); /** - * Filters all routes created by this builder with the given filter function. Filter - * functions are typically used to address cross-cutting concerns, such as logging, - * security, etc. - *

For instance, the following example creates a filter that returns a 401 Unauthorized - * response if the request does not contain the necessary authentication headers. + * Filters all routes created by this builder with the given filter + * function. Filter functions are typically used to address cross-cutting + * concerns, such as logging, security, etc. + *

For instance, the following example creates a filter that returns + * a 401 Unauthorized response if the request does not contain the + * necessary authentication headers: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .filter((request, next) -> {
-		 *       // check for authentication headers
-		 *       if (isAuthenticated(request)) {
-		 *         return next.handle(request);
-		 *       }
-		 *       else {
-		 *         return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
-		 *       }
-		 *     })
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .filter((request, next) -> {
+		 *             // check for authentication headers
+		 *             if (isAuthenticated(request)) {
+		 *                 return next.handle(request);
+		 *            }
+		 *            else {
+		 *                return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
+		 *            }
+		 *         })
+		 *         .build();
 		 * 
* @param filterFunction the function to filter all routes built by this builder + * @param the type of the {@linkplain HandlerFunction handler function} to filter + * @param the type of the response of the function * @return this builder */ - Builder filter(HandlerFilterFunction filterFunction); + Builder filter( + HandlerFilterFunction filterFunction); /** - * Filter the request object for all routes created by this builder with the given request - * processing function. Filters are typically used to address cross-cutting concerns, such - * as logging, security, etc. - *

For instance, the following example creates a filter that logs the request before - * the handler function executes. + * Filter the request object for all routes created by this builder with + * the given request processing function. Filters are typically used to + * address cross-cutting concerns, such as logging, security, etc. + *

For instance, the following example creates a filter that logs the + * request before the handler function executes: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .before(request -> {
-		 *       log(request);
-		 *       return request;
-		 *     })
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .before(request -> {
+		 *             log(request);
+		 *             return request;
+		 *         })
+		 *         .build();
 		 * 
* @param requestProcessor a function that transforms the request * @return this builder @@ -945,68 +1014,75 @@ public abstract class RouterFunctions { Builder before(Function requestProcessor); /** - * Filter the response object for all routes created by this builder with the given response - * processing function. Filters are typically used to address cross-cutting concerns, such - * as logging, security, etc. - *

For instance, the following example creates a filter that logs the response after - * the handler function executes. + * Filter the response object for all routes created by this builder + * with the given response processing function. Filters are typically + * used to address cross-cutting concerns, such as logging, security, etc. + *

For instance, the following example creates a filter that logs + * the response after the handler function executes: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .after((request, response) -> {
-		 *       log(response);
-		 *       return response;
-		 *     })
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .after((request, response) -> {
+		 *             log(response);
+		 *             return response;
+		 *          })
+		 *         .build();
 		 * 
* @param responseProcessor a function that transforms the response + * @param the type of the {@linkplain HandlerFunction handler function} to filter + * @param the type of the response of the function * @return this builder */ - Builder after(BiFunction responseProcessor); + Builder after( + BiFunction responseProcessor); /** - * Filters all exceptions that match the predicate by applying the given response provider - * function. - *

For instance, the following example creates a filter that returns a 500 response - * status when an {@code IllegalStateException} occurs. + * Filters all exceptions that match the predicate by applying the + * given response provider function. + *

For instance, the following example creates a filter that returns + * a 500 response status when an {@code IllegalStateException} occurs: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .onError(e -> e instanceof IllegalStateException,
-		 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .onError(e -> e instanceof IllegalStateException,
+		 *             (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
+		 *         .build();
 		 * 
* @param predicate the type of exception to filter * @param responseProvider a function that creates a response + * @param the type of response returned by the handler function * @return this builder */ - Builder onError(Predicate predicate, + Builder onError( + Predicate predicate, BiFunction> responseProvider); /** - * Filters all exceptions of the given type by applying the given response provider - * function. - *

For instance, the following example creates a filter that returns a 500 response - * status when an {@code IllegalStateException} occurs. + * Filters all exceptions of the given type by applying the + * given response provider function. + *

For instance, the following example creates a filter that returns + * a 500 response status when an {@code IllegalStateException} occurs: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .onError(IllegalStateException.class,
-		 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .onError(IllegalStateException.class,
+		 *             (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
+		 *         .build();
 		 * 
* @param exceptionType the type of exception to filter * @param responseProvider a function that creates a response + * @param the type of response returned by the handler function * @return this builder */ - Builder onError(Class exceptionType, + Builder onError( + Class exceptionType, BiFunction> responseProvider); /** - * Add an attribute with the given name and value to the last route built with this builder. + * Add an attribute to the last route built with this builder. * @param name the attribute name * @param value the attribute value * @return this builder @@ -1015,11 +1091,11 @@ public abstract class RouterFunctions { Builder withAttribute(String name, Object value); /** - * Manipulate the attributes of the last route built with the given consumer. - *

The map provided to the consumer is "live", so that the consumer can be used - * to {@linkplain Map#put(Object, Object) overwrite} existing attributes, - * {@linkplain Map#remove(Object) remove} attributes, or use any of the other - * {@link Map} methods. + * Manipulate the attributes of the last route built. + *

The map provided to the consumer is "live", so that the consumer + * can be used to {@linkplain Map#put(Object, Object) overwrite} existing + * attributes, {@linkplain Map#remove(Object) remove} attributes, + * or use any of the other {@link Map} methods. * @param attributesConsumer a function that consumes the attributes map * @return this builder * @since 5.3 @@ -1028,8 +1104,8 @@ public abstract class RouterFunctions { /** * Builds the {@code RouterFunction}. All created routes are - * {@linkplain RouterFunction#and(RouterFunction) composed} with one another, and filters - * (if any) are applied to the result. + * {@linkplain RouterFunction#and(RouterFunction) composed} with one + * another, and filters (if any) are applied to the result. * @return the built router function */ RouterFunction build(); @@ -1099,9 +1175,9 @@ public abstract class RouterFunctions { /** - * A composed routing function that first invokes one function, and then invokes the - * another function (of the same response type {@code T}) if this route had - * {@linkplain Mono#empty() no result}. + * A composed routing function that first invokes one function, + * and then invokes another function (of the same response type {@code T}) + * if this route had {@linkplain Mono#empty() no result}. * @param the server response type */ static final class SameComposedRouterFunction extends AbstractRouterFunction { @@ -1130,9 +1206,9 @@ public abstract class RouterFunctions { /** - * A composed routing function that first invokes one function, and then invokes - * another function (of a different response type) if this route had - * {@linkplain Mono#empty() no result}. + * A composed routing function that first invokes one function, + * and then invokes another function (of a different response type) + * if this route had {@linkplain Mono#empty() no result}. */ static final class DifferentComposedRouterFunction extends AbstractRouterFunction { @@ -1166,9 +1242,9 @@ public abstract class RouterFunctions { /** - * Filter the specified {@linkplain HandlerFunction handler functions} with the given - * {@linkplain HandlerFilterFunction filter function}. - * @param the type of the {@linkplain HandlerFunction handler function} to filter + * Filter the specified {@linkplain HandlerFunction handler functions} + * with the given {@linkplain HandlerFilterFunction filter function}. + * @param the type of the {@linkplain HandlerFunction handler function}to filter * @param the type of the response of the function */ static final class FilteredRouterFunction @@ -1254,24 +1330,24 @@ public abstract class RouterFunctions { public Mono> route(ServerRequest serverRequest) { return this.predicate.nest(serverRequest) .map(nestedRequest -> { - if (logger.isTraceEnabled()) { - String logPrefix = serverRequest.exchange().getLogPrefix(); - logger.trace(logPrefix + String.format("Matched nested %s", this.predicate)); - } - return this.routerFunction.route(nestedRequest) - .doOnNext(match -> { - if (nestedRequest != serverRequest) { - // new attributes map from nestedRequest.attributes() can be composed of the old attributes, - // which means that clearing the old attributes will remove those values from new attributes as well - // so let's make a copy - Map newAttributes = new LinkedHashMap<>(nestedRequest.attributes()); - Map oldAttributes = serverRequest.attributes(); - oldAttributes.clear(); - oldAttributes.putAll(newAttributes); - } - }); + if (logger.isTraceEnabled()) { + String logPrefix = serverRequest.exchange().getLogPrefix(); + logger.trace(logPrefix + String.format("Matched nested %s", this.predicate)); + } + return this.routerFunction.route(nestedRequest).doOnNext(match -> { + if (nestedRequest != serverRequest) { + // new attributes map from nestedRequest.attributes() can be composed of + // the old attributes, which means clearing the old attributes will + // remove those values from new attributes as well + // so let's make a copy + Map newAttributes = new LinkedHashMap<>(nestedRequest.attributes()); + Map oldAttributes = serverRequest.attributes(); + oldAttributes.clear(); + oldAttributes.putAll(newAttributes); } - ).orElseGet(Mono::empty); + }); + }) + .orElseGet(Mono::empty); } @@ -1302,7 +1378,8 @@ public abstract class RouterFunctions { @Override public Mono> route(ServerRequest request) { - return this.lookupFunction.apply(request).map(resource -> new ResourceHandlerFunction(resource, this.headersConsumer)); + return this.lookupFunction.apply(request) + .map(resource -> new ResourceHandlerFunction(resource, this.headersConsumer)); } @Override @@ -1324,12 +1401,8 @@ public abstract class RouterFunctions { } private static Map initAttributes(Map attributes) { - if (attributes.isEmpty()) { - return Collections.emptyMap(); - } - else { - return Collections.unmodifiableMap(new LinkedHashMap<>(attributes)); - } + return (attributes.isEmpty() ? + Collections.emptyMap() : Collections.unmodifiableMap(new LinkedHashMap<>(attributes))); } @Override diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctionBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctionBuilder.java index 3dcca5e687c..4505ac7b7ff 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctionBuilder.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctionBuilder.java @@ -58,25 +58,29 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { return this; } - private RouterFunctions.Builder add(RequestPredicate predicate, HandlerFunction handlerFunction) { + private RouterFunctions.Builder add( + RequestPredicate predicate, HandlerFunction handlerFunction) { + return add(RouterFunctions.route(predicate, handlerFunction)); } // GET @Override - public RouterFunctions.Builder GET(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.GET), handlerFunction); + public RouterFunctions.Builder GET(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.GET), function); } @Override - public RouterFunctions.Builder GET(RequestPredicate predicate, HandlerFunction handlerFunction) { + public RouterFunctions.Builder GET( + RequestPredicate predicate, HandlerFunction handlerFunction) { + return add(RequestPredicates.method(HttpMethod.GET).and(predicate), handlerFunction); } @Override - public RouterFunctions.Builder GET(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.GET(pattern), handlerFunction); + public RouterFunctions.Builder GET(String pattern, HandlerFunction function) { + return add(RequestPredicates.GET(pattern), function); } @Override @@ -94,18 +98,20 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder HEAD(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.HEAD).and(predicate), handlerFunction); + public RouterFunctions.Builder HEAD( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.HEAD).and(predicate), function); } @Override - public RouterFunctions.Builder HEAD(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.HEAD(pattern), handlerFunction); + public RouterFunctions.Builder HEAD(String pattern, HandlerFunction function) { + return add(RequestPredicates.HEAD(pattern), function); } @Override - public RouterFunctions.Builder HEAD(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder HEAD( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction) { return add(RequestPredicates.HEAD(pattern).and(predicate), handlerFunction); } @@ -118,18 +124,20 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder POST(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.POST).and(predicate), handlerFunction); + public RouterFunctions.Builder POST( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.POST).and(predicate), function); } @Override - public RouterFunctions.Builder POST(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.POST(pattern), handlerFunction); + public RouterFunctions.Builder POST(String pattern, HandlerFunction function) { + return add(RequestPredicates.POST(pattern), function); } @Override - public RouterFunctions.Builder POST(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder POST( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction) { return add(RequestPredicates.POST(pattern).and(predicate), handlerFunction); } @@ -137,105 +145,114 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { // PUT @Override - public RouterFunctions.Builder PUT(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PUT), handlerFunction); + public RouterFunctions.Builder PUT(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.PUT), function); } @Override - public RouterFunctions.Builder PUT(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PUT).and(predicate), handlerFunction); + public RouterFunctions.Builder PUT( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.PUT).and(predicate), function); } @Override - public RouterFunctions.Builder PUT(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.PUT(pattern), handlerFunction); + public RouterFunctions.Builder PUT(String pattern, HandlerFunction function) { + return add(RequestPredicates.PUT(pattern), function); } @Override - public RouterFunctions.Builder PUT(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder PUT( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.PUT(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.PUT(pattern).and(predicate), function); } // PATCH @Override - public RouterFunctions.Builder PATCH(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PATCH), handlerFunction); + public RouterFunctions.Builder PATCH(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.PATCH), function); } @Override - public RouterFunctions.Builder PATCH(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.PATCH).and(predicate), handlerFunction); + public RouterFunctions.Builder PATCH( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.PATCH).and(predicate), function); } @Override - public RouterFunctions.Builder PATCH(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.PATCH(pattern), handlerFunction); + public RouterFunctions.Builder PATCH(String pattern, HandlerFunction function) { + return add(RequestPredicates.PATCH(pattern), function); } @Override - public RouterFunctions.Builder PATCH(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder PATCH( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.PATCH(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.PATCH(pattern).and(predicate), function); } // DELETE @Override - public RouterFunctions.Builder DELETE(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.DELETE), handlerFunction); + public RouterFunctions.Builder DELETE(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.DELETE), function); } @Override - public RouterFunctions.Builder DELETE(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.DELETE).and(predicate), handlerFunction); + public RouterFunctions.Builder DELETE( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.DELETE).and(predicate), function); } @Override - public RouterFunctions.Builder DELETE(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.DELETE(pattern), handlerFunction); + public RouterFunctions.Builder DELETE(String pattern, HandlerFunction function) { + return add(RequestPredicates.DELETE(pattern), function); } @Override - public RouterFunctions.Builder DELETE(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder DELETE( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.DELETE(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.DELETE(pattern).and(predicate), function); } // OPTIONS @Override - public RouterFunctions.Builder OPTIONS(HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.OPTIONS), handlerFunction); + public RouterFunctions.Builder OPTIONS(HandlerFunction function) { + return add(RequestPredicates.method(HttpMethod.OPTIONS), function); } @Override - public RouterFunctions.Builder OPTIONS(RequestPredicate predicate, HandlerFunction handlerFunction) { - return add(RequestPredicates.method(HttpMethod.OPTIONS).and(predicate), handlerFunction); + public RouterFunctions.Builder OPTIONS( + RequestPredicate predicate, HandlerFunction function) { + + return add(RequestPredicates.method(HttpMethod.OPTIONS).and(predicate), function); } @Override - public RouterFunctions.Builder OPTIONS(String pattern, HandlerFunction handlerFunction) { - return add(RequestPredicates.OPTIONS(pattern), handlerFunction); + public RouterFunctions.Builder OPTIONS(String pattern, HandlerFunction function) { + return add(RequestPredicates.OPTIONS(pattern), function); } @Override - public RouterFunctions.Builder OPTIONS(String pattern, RequestPredicate predicate, - HandlerFunction handlerFunction) { + public RouterFunctions.Builder OPTIONS( + String pattern, RequestPredicate predicate, HandlerFunction function) { - return add(RequestPredicates.OPTIONS(pattern).and(predicate), handlerFunction); + return add(RequestPredicates.OPTIONS(pattern).and(predicate), function); } // other @Override - public RouterFunctions.Builder route(RequestPredicate predicate, - HandlerFunction handlerFunction) { - return add(RouterFunctions.route(predicate, handlerFunction)); + public RouterFunctions.Builder route( + RequestPredicate predicate, HandlerFunction function) { + + return add(RouterFunctions.route(predicate, function)); } @Override @@ -244,8 +261,9 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder resource(RequestPredicate predicate, Resource resource, - BiConsumer headersConsumer) { + public RouterFunctions.Builder resource( + RequestPredicate predicate, Resource resource, BiConsumer headersConsumer) { + return add(RouterFunctions.resource(predicate, resource, headersConsumer)); } @@ -267,15 +285,16 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder resources(Function> lookupFunction, + public RouterFunctions.Builder resources( + Function> lookupFunction, BiConsumer headersConsumer) { return add(RouterFunctions.resources(lookupFunction, headersConsumer)); } @Override - public RouterFunctions.Builder nest(RequestPredicate predicate, - Consumer builderConsumer) { + public RouterFunctions.Builder nest( + RequestPredicate predicate, Consumer builderConsumer) { Assert.notNull(builderConsumer, "Consumer must not be null"); @@ -288,35 +307,34 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { @SuppressWarnings("unchecked") @Override - public RouterFunctions.Builder nest(RequestPredicate predicate, - Supplier> routerFunctionSupplier) { + public RouterFunctions.Builder nest( + RequestPredicate predicate, Supplier> routerFunctionSupplier) { Assert.notNull(routerFunctionSupplier, "RouterFunction Supplier must not be null"); - RouterFunction nestedRoute = (RouterFunction) routerFunctionSupplier.get(); - this.routerFunctions.add(RouterFunctions.nest(predicate, nestedRoute)); + RouterFunction route = (RouterFunction) routerFunctionSupplier.get(); + this.routerFunctions.add(RouterFunctions.nest(predicate, route)); return this; } @Override - public RouterFunctions.Builder path(String pattern, - Consumer builderConsumer) { - + public RouterFunctions.Builder path(String pattern, Consumer builderConsumer) { return nest(RequestPredicates.path(pattern), builderConsumer); } @Override - public RouterFunctions.Builder path(String pattern, - Supplier> routerFunctionSupplier) { + public RouterFunctions.Builder path( + String pattern, Supplier> routerFunctionSupplier) { return nest(RequestPredicates.path(pattern), routerFunctionSupplier); } @SuppressWarnings("unchecked") @Override - public RouterFunctions.Builder filter(HandlerFilterFunction filterFunction) { - Assert.notNull(filterFunction, "HandlerFilterFunction must not be null"); + public RouterFunctions.Builder filter( + HandlerFilterFunction filterFunction) { + Assert.notNull(filterFunction, "HandlerFilterFunction must not be null"); this.filterFunctions.add((HandlerFilterFunction) filterFunction); return this; } @@ -337,8 +355,8 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { @SuppressWarnings("unchecked") @Override - public RouterFunctions.Builder onError(Predicate predicate, - BiFunction responseProvider) { + public RouterFunctions.Builder onError( + Predicate predicate, BiFunction responseProvider) { Assert.notNull(predicate, "Predicate must not be null"); Assert.notNull(responseProvider, "ResponseProvider must not be null"); @@ -349,8 +367,9 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { } @Override - public RouterFunctions.Builder onError(Class exceptionType, - BiFunction responseProvider) { + public RouterFunctions.Builder onError( + Class exceptionType, BiFunction responseProvider) { + Assert.notNull(exceptionType, "ExceptionType must not be null"); Assert.notNull(responseProvider, "ResponseProvider must not be null"); @@ -361,49 +380,41 @@ class RouterFunctionBuilder implements RouterFunctions.Builder { public RouterFunctions.Builder withAttribute(String name, Object value) { Assert.hasLength(name, "Name must not be empty"); Assert.notNull(value, "Value must not be null"); - - if (this.routerFunctions.isEmpty()) { - throw new IllegalStateException("attributes can only be called after any other method (GET, path, etc.)"); - } + Assert.state(!this.routerFunctions.isEmpty(), + "attributes can only be called after any other method (GET, path, etc.)"); int lastIdx = this.routerFunctions.size() - 1; - RouterFunction attributed = this.routerFunctions.get(lastIdx) - .withAttribute(name, value); + RouterFunction attributed = this.routerFunctions.get(lastIdx).withAttribute(name, value); this.routerFunctions.set(lastIdx, attributed); return this; } @Override - public RouterFunctions.Builder withAttributes(Consumer> attributesConsumer) { - Assert.notNull(attributesConsumer, "AttributesConsumer must not be null"); - - if (this.routerFunctions.isEmpty()) { - throw new IllegalStateException("attributes can only be called after any other method (GET, path, etc.)"); - } + public RouterFunctions.Builder withAttributes(Consumer> consumer) { + Assert.notNull(consumer, "AttributesConsumer must not be null"); + Assert.state(!this.routerFunctions.isEmpty(), + "attributes can only be called after any other method (GET, path, etc.)"); int lastIdx = this.routerFunctions.size() - 1; - RouterFunction attributed = this.routerFunctions.get(lastIdx) - .withAttributes(attributesConsumer); + RouterFunction attributed = this.routerFunctions.get(lastIdx).withAttributes(consumer); this.routerFunctions.set(lastIdx, attributed); return this; } @Override public RouterFunction build() { - if (this.routerFunctions.isEmpty()) { - throw new IllegalStateException("No routes registered. Register a route with GET(), POST(), etc."); - } - RouterFunction result = new BuiltRouterFunction(this.routerFunctions); + Assert.state(!this.routerFunctions.isEmpty(), + "No routes registered. Register a route with GET(), POST(), etc."); + RouterFunction result = new BuiltRouterFunction(this.routerFunctions); if (this.filterFunctions.isEmpty() && this.errorHandlers.isEmpty()) { return result; } - else { - HandlerFilterFunction filter = - Stream.concat(this.filterFunctions.stream(), this.errorHandlers.stream()) - .reduce(HandlerFilterFunction::andThen) - .orElseThrow(IllegalStateException::new); - return result.filter(filter); - } + HandlerFilterFunction filter = + Stream.concat(this.filterFunctions.stream(), this.errorHandlers.stream()) + .reduce(HandlerFilterFunction::andThen) + .orElseThrow(IllegalStateException::new); + + return result.filter(filter); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctions.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctions.java index afa6983a8b5..d08d6955466 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctions.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/function/RouterFunctions.java @@ -36,13 +36,14 @@ import org.springframework.util.Assert; import org.springframework.web.util.pattern.PathPatternParser; /** - * Central entry point to Spring's functional web framework. + * Main entry point to Spring's functional WebMvc framework. * Exposes routing functionality, such as to {@linkplain #route() create} a * {@code RouterFunction} using a discoverable builder-style API, to - * {@linkplain #route(RequestPredicate, HandlerFunction) create} a {@code RouterFunction} - * given a {@code RequestPredicate} and {@code HandlerFunction}, and to do further - * {@linkplain #nest(RequestPredicate, RouterFunction) subrouting} on an existing routing - * function. + * {@linkplain #route(RequestPredicate, HandlerFunction) create} a + * {@code RouterFunction} given a {@code RequestPredicate} and + * {@code HandlerFunction}, and to do further + * {@linkplain #nest(RequestPredicate, RouterFunction) subrouting} on an + * existing routing function. * * @author Arjen Poutsma * @author Sebastien Deleuze @@ -103,19 +104,21 @@ public abstract class RouterFunctions { } /** - * Route to the given router function if the given request predicate applies. This method can be - * used to create nested routes, where a group of routes share a common path - * (prefix), header, or other request predicate. - *

For instance, the following example first creates a composed route that resolves to - * {@code listUsers} for a GET, and {@code createUser} for a POST. This composed route then gets - * nested with a "/user" path predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * Route to the given router function if the given request predicate applies. + * This can be used to create nested routes where a group + * of routes share a common path (prefix), header, or other request predicate. + *

For instance, the following example first creates a composed route that + * resolves to {@code listUsers} for a GET, and {@code createUser} for a POST. + * This composed route then gets nested with a "/user" path predicate, + * so that GET requests for "/user" will list users, and POST request for + * "/user" will create a new user. *

 	 * RouterFunction<ServerResponse> userRoutes =
-	 *   RouterFunctions.route(RequestPredicates.method(HttpMethod.GET), this::listUsers)
-	 *     .andRoute(RequestPredicates.method(HttpMethod.POST), this::createUser);
+	 *     RouterFunctions.route(RequestPredicates.method(HttpMethod.GET), this::listUsers)
+	 *         .andRoute(RequestPredicates.method(HttpMethod.POST), this::createUser);
+	 *
 	 * RouterFunction<ServerResponse> nestedRoute =
-	 *   RouterFunctions.nest(RequestPredicates.path("/user"), userRoutes);
+	 *     RouterFunctions.nest(RequestPredicates.path("/user"), userRoutes);
 	 * 
* @param predicate the predicate to test * @param routerFunction the nested router function to delegate to if the predicate applies @@ -132,9 +135,9 @@ public abstract class RouterFunctions { /** * Route requests that match the given predicate to the given resource. - * For instance + * For instance: *
-	 * Resource resource = new ClassPathResource("static/index.html")
+	 * Resource resource = new ClassPathResource("static/index.html");
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resource(path("/api/**").negate(), resource);
 	 * 
* @param predicate the predicate to match @@ -148,7 +151,7 @@ public abstract class RouterFunctions { /** * Route requests that match the given predicate to the given resource. - * For instance + * For instance: *
 	 * Resource resource = new ClassPathResource("static/index.html")
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resource(path("/api/**").negate(), resource);
@@ -159,15 +162,15 @@ public abstract class RouterFunctions {
 	 * @return a router function that routes to a resource
 	 * @since 6.1.4
 	 */
-	public static RouterFunction resource(RequestPredicate predicate, Resource resource,
-			BiConsumer headersConsumer) {
+	public static RouterFunction resource(
+			RequestPredicate predicate, Resource resource,BiConsumer headersConsumer) {
 
 		return resources(new PredicateResourceLookupFunction(predicate, resource), headersConsumer);
 	}
 
 	/**
-	 * Route requests that match the given pattern to resources relative to the given root location.
-	 * For instance
+	 * Route requests that match the given pattern to resources relative to the
+	 * given root location. For instance:
 	 * 
 	 * Resource location = new FileUrlResource("public-resources/");
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -183,8 +186,8 @@ public abstract class RouterFunctions {
 	}
 
 	/**
-	 * Route requests that match the given pattern to resources relative to the given root location.
-	 * For instance
+	 * Route requests that match the given pattern to resources relative to the
+	 * given root location. For instance:
 	 * 
 	 * Resource location = new FileUrlResource("public-resources/");
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -197,21 +200,24 @@ public abstract class RouterFunctions {
 	 * @see org.springframework.web.util.pattern.PathPattern
 	 * @see #resourceLookupFunction(String, Resource)
 	 */
-	public static RouterFunction resources(String pattern, Resource location,
-			BiConsumer headersConsumer) {
+	public static RouterFunction resources(
+			String pattern, Resource location, BiConsumer headersConsumer) {
 
 		return resources(resourceLookupFunction(pattern, location), headersConsumer);
 	}
 
 	/**
-	 * Returns the resource lookup function used by {@link #resources(String, Resource)}.
-	 * The returned function can be {@linkplain Function#andThen(Function) composed} on, for
-	 * instance to return a default resource when the lookup function does not match:
+	 * Returns the resource lookup function used by
+	 * {@link #resources(String, Resource)}. The returned function can be
+	 * {@linkplain Function#andThen(Function) composed} on. For instance to
+	 * return a default resource when the lookup function does not match:
 	 * 
 	 * Optional<Resource> defaultResource = Optional.of(new ClassPathResource("index.html"));
+	 *
 	 * Function<ServerRequest, Optional<Resource>> lookupFunction =
-	 *   RouterFunctions.resourceLookupFunction("/resources/**", new FileUrlResource("public-resources/"))
-	 *     .andThen(resource -> resource.or(() -> defaultResource));
+	 *     RouterFunctions.resourceLookupFunction("/resources/**", new FileUrlResource("public-resources/"))
+	 *         .andThen(resource -> resource.or(() -> defaultResource));
+	 *
 	 * RouterFunction<ServerResponse> resources = RouterFunctions.resources(lookupFunction);
      * 
* @param pattern the pattern to match @@ -219,18 +225,23 @@ public abstract class RouterFunctions { * @return the default resource lookup function for the given parameters. * @see org.springframework.web.util.pattern.PathPattern */ - public static Function> resourceLookupFunction(String pattern, Resource location) { + public static Function> resourceLookupFunction( + String pattern, Resource location) { + return new PathResourceLookupFunction(pattern, location); } /** - * Route to resources using the provided lookup function. If the lookup function provides a - * {@link Resource} for the given request, it will be it will be exposed using a - * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests. - * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest} + * Route to resources using the provided lookup function. If the lookup + * function provides a {@link Resource} for the given request, it will be + * it will be exposed using a {@link HandlerFunction} that handles + * GET, HEAD, and OPTIONS requests. + * @param lookupFunction the function to provide a {@link Resource} * @return a router function that routes to resources */ - public static RouterFunction resources(Function> lookupFunction) { + public static RouterFunction resources( + Function> lookupFunction) { + return new ResourcesRouterFunction(lookupFunction, (resource, httpHeaders) -> {}); } @@ -238,12 +249,13 @@ public abstract class RouterFunctions { * Route to resources using the provided lookup function. If the lookup function provides a * {@link Resource} for the given request, it will be it will be exposed using a * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests. - * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest} + * @param lookupFunction the function to provide a {@link Resource} * @param headersConsumer provides access to the HTTP headers for served resources * @return a router function that routes to resources * @since 6.1 */ - public static RouterFunction resources(Function> lookupFunction, + public static RouterFunction resources( + Function> lookupFunction, BiConsumer headersConsumer) { return new ResourcesRouterFunction(lookupFunction, headersConsumer); @@ -251,8 +263,10 @@ public abstract class RouterFunctions { /** - * Changes the {@link PathPatternParser} on the given {@linkplain RouterFunction router function}. This method - * can be used to change the {@code PathPatternParser} properties from the defaults, for instance to change + * Changes the {@link PathPatternParser} on the given + * {@linkplain RouterFunction router function}. This method can be used to + * change the {@code PathPatternParser} properties from the defaults. + * For instance to change * {@linkplain PathPatternParser#setCaseSensitive(boolean) case sensitivity}. * @param routerFunction the router function to change the parser in * @param parser the parser to change to @@ -278,30 +292,32 @@ public abstract class RouterFunctions { public interface Builder { /** - * Adds a route to the given handler function that handles HTTP {@code GET} requests. - * @param handlerFunction the handler function to handle all {@code GET} requests + * Adds a route to the given handler function that handles + * HTTP {@code GET} requests. + * @param handlerFunction handler for all {@code GET} requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder GET(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code GET} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code GET} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code GET} requests that - * match {@code pattern} + * @param handlerFunction handler for all GET requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder GET(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code GET} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code GET} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code GET} requests that - * match {@code predicate} + * @param handlerFunction handler for all GET requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates @@ -309,334 +325,365 @@ public abstract class RouterFunctions { Builder GET(RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code GET} requests - * that match the given pattern and predicate. - *

For instance, the following example routes GET requests for "/user" that accept JSON - * to the {@code listUsers} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code GET} requests that match the given pattern and predicate. + *

For instance, the below routes GET requests for "/user" that accept + * JSON to the {@code listUsers} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userController::listUsers)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", RequestPredicates.accept(MediaType.APPLICATION_JSON), userController::listUsers)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match * @param handlerFunction the handler function to handle all {@code GET} requests that * match {@code pattern} and the predicate + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern * @see RequestPredicates */ - Builder GET(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder GET( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code HEAD} requests. - * @param handlerFunction the handler function to handle all {@code HEAD} requests + * Adds a route to the given handler function that handles + * HTTP {@code HEAD} requests. + * @param handlerFunction handler for all {@code HEAD} requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder HEAD(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code HEAD} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code HEAD} requests that - * match {@code pattern} + * @param handlerFunction handler for HEAD requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder HEAD(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code HEAD} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code HEAD} requests that - * match {@code predicate} + * @param handlerFunction handler for HEAD requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder HEAD(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder HEAD( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code HEAD} requests - * that match the given pattern and predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code HEAD} requests that match the given pattern and predicate. * @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code HEAD} requests that - * match {@code pattern} + * @param handlerFunction handler for HEAD requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder HEAD(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder HEAD( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code POST} requests. - * @param handlerFunction the handler function to handle all {@code POST} requests + * Adds a route to the given handler function that handles + * HTTP {@code POST} requests. + * @param handlerFunction handler for all {@code POST} requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder POST(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code POST} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code POST} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code POST} requests that - * match {@code pattern} + * @param handlerFunction handler for POST requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder POST(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code POST} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code POST} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code POST} requests that - * match {@code predicate} + * @param handlerFunction handler for POST requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder POST(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder POST( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code POST} requests - * that match the given pattern and predicate. - *

For instance, the following example routes POST requests for "/user" that contain JSON - * to the {@code addUser} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code POST} requests that match the given pattern and predicate. + *

For instance, the below routes POST requests for "/user" that + * contain JSON to the {@code addUser} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .POST("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::addUser)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .POST("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::addUser)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code POST} requests that - * match {@code pattern} + * @param handlerFunction handler for all POST requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder POST(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder POST( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code PUT} requests. - * @param handlerFunction the handler function to handle all {@code PUT} requests + * Adds a route to the given handler function that handles + * HTTP {@code PUT} requests. + * @param handlerFunction handler for all {@code PUT} requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder PUT(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PUT} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code PUT} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code PUT} requests that - * match {@code pattern} + * @param handlerFunction handler for all PUT requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder PUT(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PUT} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code PUT} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code PUT} requests that - * match {@code predicate} + * @param handlerFunction handler for PUT requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder PUT(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PUT( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PUT} requests - * that match the given pattern and predicate. - *

For instance, the following example routes PUT requests for "/user" that contain JSON - * to the {@code editUser} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code PUT} requests that match the given pattern and predicate. + *

For instance, the below routes PUT requests for "/user" that + * contain JSON to the {@code editUser} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .PUT("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .PUT("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code PUT} requests that - * match {@code pattern} + * @param handlerFunction handler for PUT requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder PUT(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PUT( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code PATCH} requests. - * @param handlerFunction the handler function to handle all {@code PATCH} requests + * Adds a route to the given handler function that handles + * HTTP {@code PATCH} requests. + * @param handlerFunction handler for all {@code PATCH} requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder PATCH(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code PATCH} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code PATCH} requests that - * match {@code pattern} + * @param handlerFunction handler for PATCH requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ Builder PATCH(String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code PATCH} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code PATCH} requests that - * match {@code predicate} + * @param handlerFunction handler for PATCH requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder PATCH(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PATCH( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code PATCH} requests - * that match the given pattern and predicate. - *

For instance, the following example routes PATCH requests for "/user" that contain JSON - * to the {@code editUser} method in {@code userController}: + * Adds a route to the given handler function that handles all + * HTTP {@code PATCH} requests that match the given pattern and predicate. + *

For instance, the below routes PATCH requests for "/user" that + * contain JSON to the {@code editUser} method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .PATCH("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .PATCH("/user", RequestPredicates.contentType(MediaType.APPLICATION_JSON), userController::editUser)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code PATCH} requests that - * match {@code pattern} + * @param handlerFunction handler for PATCH requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder PATCH(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder PATCH( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code DELETE} requests. - * @param handlerFunction the handler function to handle all {@code DELETE} requests + * Adds a route to the given handler function that handles + * HTTP {@code DELETE} requests. + * @param handlerFunction handler for all {@code DELETE} requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder DELETE(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code DELETE} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code DELETE} requests that - * match {@code pattern} + * @param handlerFunction handler for DELETE requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder DELETE(String pattern, HandlerFunction handlerFunction); + Builder DELETE( + String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code DELETE} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code DELETE} requests that - * match {@code predicate} + * @param handlerFunction handler for DELETE requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder DELETE(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder DELETE( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code DELETE} requests - * that match the given pattern and predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code DELETE} requests that match the given pattern and predicate. * @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code DELETE} requests that - * match {@code pattern} + * @param handlerFunction handler for DELETE requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder DELETE(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder DELETE( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles HTTP {@code OPTIONS} requests. - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests + * Adds a route to the given handler function that handles + * HTTP {@code OPTIONS} requests. + * @param handlerFunction handler for OPTIONS requests + * @param the type of response returned by the handler function * @return this builder * @since 5.3 */ Builder OPTIONS(HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests - * that match the given pattern. + * Adds a route to the given handler function that handles all + * HTTP {@code OPTIONS} requests that match the given pattern. * @param pattern the pattern to match to - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that - * match {@code pattern} + * @param handlerFunction handler for OPTIONS requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder OPTIONS(String pattern, HandlerFunction handlerFunction); + Builder OPTIONS( + String pattern, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests - * that match the given predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code OPTIONS} requests that match the given predicate. * @param predicate the predicate to match - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that - * match {@code predicate} + * @param handlerFunction handler for OPTIONS requests that match {@code predicate} + * @param the type of response returned by the handler function * @return this builder * @since 5.3 * @see RequestPredicates */ - Builder OPTIONS(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder OPTIONS( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all HTTP {@code OPTIONS} requests - * that match the given pattern and predicate. + * Adds a route to the given handler function that handles all + * HTTP {@code OPTIONS} requests that match the given pattern and predicate. * @param pattern the pattern to match to * @param predicate additional predicate to match - * @param handlerFunction the handler function to handle all {@code OPTIONS} requests that - * match {@code pattern} + * @param handlerFunction handler for OPTIONS requests that match {@code pattern} + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder OPTIONS(String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); + Builder OPTIONS( + String pattern, RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds a route to the given handler function that handles all requests that match the - * given predicate. + * Adds a route to the given handler function that handles all requests + * that match the given predicate. * @param predicate the request predicate to match - * @param handlerFunction the handler function to handle all requests that match the predicate + * @param handlerFunction handler for all requests that match the predicate + * @param the type of response returned by the handler function * @return this builder * @see RequestPredicates */ - Builder route(RequestPredicate predicate, HandlerFunction handlerFunction); + Builder route( + RequestPredicate predicate, HandlerFunction handlerFunction); /** - * Adds the given route to this builder. Can be used to merge externally defined router - * functions into this builder, or can be combined with + * Adds the given route to this builder. Can be used to merge externally + * defined router functions into this builder, or can be combined with * {@link RouterFunctions#route(RequestPredicate, HandlerFunction)} * to allow for more flexible predicate matching. - *

For instance, the following example adds the router function returned from - * {@code OrderController.routerFunction()}. - * to the {@code changeUser} method in {@code userController}: + *

For instance, the below adds the router function returned from + * {@code OrderController.routerFunction()} to the {@code changeUser} + * method in {@code userController}: *

 		 * RouterFunction<ServerResponse> route =
-		 *   RouterFunctions.route()
-		 *     .GET("/users", userController::listUsers)
-		 *     .add(orderController.routerFunction());
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/users", userController::listUsers)
+		 *         .add(orderController.routerFunction());
+		 *         .build();
 		 * 
* @param routerFunction the router function to be added + * @param the type of response returned by the handler function * @return this builder * @see RequestPredicates */ @@ -644,7 +691,7 @@ public abstract class RouterFunctions { /** * Route requests that match the given predicate to the given resource. - * For instance + * For instance: *
 		 * Resource resource = new ClassPathResource("static/index.html")
 		 * RouterFunction<ServerResponse> resources = RouterFunctions.resource(path("/api/**").negate(), resource);
@@ -658,7 +705,7 @@ public abstract class RouterFunctions {
 
 		/**
 		 * Route requests that match the given predicate to the given resource.
-		 * For instance
+		 * For instance:
 		 * 
 		 * Resource resource = new ClassPathResource("static/index.html")
 		 * RouterFunction<ServerResponse> resources = RouterFunctions.resource(path("/api/**").negate(), resource);
@@ -669,11 +716,13 @@ public abstract class RouterFunctions {
 		 * @return a router function that routes to a resource
 		 * @since 6.1.4
 		 */
-		Builder resource(RequestPredicate predicate, Resource resource, BiConsumer headersConsumer);
+		Builder resource(
+				RequestPredicate predicate, Resource resource,
+				BiConsumer headersConsumer);
 
 		/**
-		 * Route requests that match the given pattern to resources relative to the given root location.
-		 * For instance
+		 * Route requests that match the given pattern to resources relative
+		 * to the given root location. For instance:
 		 * 
 		 * Resource location = new FileUrlResource("public-resources/");
 		 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -686,8 +735,8 @@ public abstract class RouterFunctions {
 		Builder resources(String pattern, Resource location);
 
 		/**
-		 * Route requests that match the given pattern to resources relative to the given root location.
-		 * For instance
+		 * Route requests that match the given pattern to resources relative to
+		 * the given root location. For instance:
 		 * 
 		 * Resource location = new FileUrlResource("public-resources/");
 		 * RouterFunction<ServerResponse> resources = RouterFunctions.resources("/resources/**", location);
@@ -699,113 +748,125 @@ public abstract class RouterFunctions {
 		 * @since 6.1
 		 * @see org.springframework.web.util.pattern.PathPattern
 		 */
-		Builder resources(String pattern, Resource location, BiConsumer headersConsumer);
+		Builder resources(
+				String pattern, Resource location,
+				BiConsumer headersConsumer);
 
 		/**
-		 * Route to resources using the provided lookup function. If the lookup function provides a
-		 * {@link Resource} for the given request, it will be it will be exposed using a
-		 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
-		 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
+		 * Route to resources using the provided lookup function.
+		 * If the lookup function provides a {@link Resource} for the given
+		 * request, it will be it will be exposed using a {@link HandlerFunction}
+		 * that handles GET, HEAD, and OPTIONS requests.
+		 * @param lookupFunction the function to provide a {@link Resource}
 		 * @return this builder
 		 */
 		Builder resources(Function> lookupFunction);
 
 		/**
-		 * Route to resources using the provided lookup function. If the lookup function provides a
-		 * {@link Resource} for the given request, it will be it will be exposed using a
-		 * {@link HandlerFunction} that handles GET, HEAD, and OPTIONS requests.
-		 * @param lookupFunction the function to provide a {@link Resource} given the {@link ServerRequest}
+		 * Route to resources using the provided lookup function.
+		 * If the lookup function provides a {@link Resource} for the given
+		 * request, it will be it will be exposed using a {@link HandlerFunction}
+		 * that handles GET, HEAD, and OPTIONS requests.
+		 * @param lookupFunction the function to provide a {@link Resource}
 		 * @param headersConsumer provides access to the HTTP headers for served resources
 		 * @return this builder
 		 * @since 6.1
 		 */
-		Builder resources(Function> lookupFunction, BiConsumer headersConsumer);
+		Builder resources(
+				Function> lookupFunction,
+				BiConsumer headersConsumer);
 
 		/**
-		 * Route to the supplied router function if the given request predicate applies. This method
-		 * can be used to create nested routes, where a group of routes share a
-		 * common path (prefix), header, or other request predicate.
-		 * 

For instance, the following example creates a nested route with a "/user" path - * predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * Route to the supplied router function if the given request predicate + * applies. This method can be used to create nested routes, + * where a group of routes share a common path (prefix), header, or other + * request predicate. + *

For instance, the below creates a nested route with a "/user" path + * predicate, so that GET requests for "/user" will list users, and POST + * request for "/user" will create a new user: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .nest(RequestPredicates.path("/user"), () ->
-		 *       RouterFunctions.route()
-		 *         .GET(this::listUsers)
-		 *         .POST(this::createUser)
-		 *         .build())
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .nest(RequestPredicates.path("/user"), () ->
+		 *             RouterFunctions.route()
+		 *                 .GET(this::listUsers)
+		 *                 .POST(this::createUser)
+		 *                 .build())
+		 *         .build();
 		 * 
* @param predicate the predicate to test - * @param routerFunctionSupplier supplier for the nested router function to delegate to if - * the predicate applies + * @param routerFunctionSupplier supplier for the nested router function + * to delegate to if the predicate applies + * @param the type of response returned by the handler function * @return this builder * @see RequestPredicates */ - Builder nest(RequestPredicate predicate, Supplier> routerFunctionSupplier); + Builder nest( + RequestPredicate predicate, Supplier> routerFunctionSupplier); /** * Route to a built router function if the given request predicate applies. - * This method can be used to create nested routes, where a group of routes - * share a common path (prefix), header, or other request predicate. - *

For instance, the following example creates a nested route with a "/user" path - * predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * This method can be used to create nested routes, + * where a group of routes share a common path (prefix), header, + * or other request predicate. + *

For instance, the below creates a nested route with a "/user" path + * predicate, so that GET requests for "/user" will list users, and POST + * request for "/user" will create a new user: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .nest(RequestPredicates.path("/user"), builder ->
-		 *       builder.GET(this::listUsers)
-		 *              .POST(this::createUser))
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .nest(RequestPredicates.path("/user"), builder ->
+		 *             builder.GET(this::listUsers).POST(this::createUser))
+		 *         .build();
 		 * 
* @param predicate the predicate to test - * @param builderConsumer consumer for a {@code Builder} that provides the nested router - * function + * @param builderConsumer consumer for a {@code Builder} that provides + * the nested router function * @return this builder * @see RequestPredicates */ Builder nest(RequestPredicate predicate, Consumer builderConsumer); /** - * Route to the supplied router function if the given path prefix pattern applies. This method - * can be used to create nested routes, where a group of routes share a - * common path prefix. Specifically, this method can be used to merge externally defined - * router functions under a path prefix. - *

For instance, the following example creates a nested route with a "/user" path - * predicate that delegates to the router function defined in {@code userController}, - * and with a "/order" path that delegates to {@code orderController}. + * Route to the supplied router function if the given path prefix + * pattern applies. This method can be used to create + * nested routes, where a group of routes share a common + * path prefix. Specifically, this method can be used to merge externally + * defined router functions under a path prefix. + *

For instance, the below creates a nested route with a "/user" path + * predicate that delegates to the router function defined in + * {@code userController}, and with a "/order" path that delegates to + * {@code orderController}: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .path("/user", userController::routerFunction)
-		 *     .path("/order", orderController::routerFunction)
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .path("/user", userController::routerFunction)
+		 *         .path("/order", orderController::routerFunction)
+		 *         .build();
 		 * 
* @param pattern the pattern to match to - * @param routerFunctionSupplier supplier for the nested router function to delegate to if - * the pattern matches + * @param routerFunctionSupplier supplier for the nested router function + * to delegate to if the pattern matches + * @param the type of response returned by the handler function * @return this builder * @see org.springframework.web.util.pattern.PathPattern */ - Builder path(String pattern, Supplier> routerFunctionSupplier); + Builder path( + String pattern, Supplier> routerFunctionSupplier); /** - * Route to a built router function if the given path prefix pattern applies. - * This method can be used to create nested routes, where a group of routes - * share a common path prefix. - *

For instance, the following example creates a nested route with a "/user" path - * predicate, so that GET requests for "/user" will list users, - * and POST request for "/user" will create a new user. + * Route to a built router function if the given path prefix pattern + * applies. This method can be used to create + * nested routes, where a group of routes share a + * common path prefix. + *

For instance, the below creates a nested route with a "/user" path + * predicate, so that GET requests for "/user" will list users, and POST + * request for "/user" will create a new user: *

 		 * RouterFunction<ServerResponse> nestedRoute =
-		 *   RouterFunctions.route()
-		 *     .path("/user", builder ->
-		 *       builder.GET(this::listUsers)
-		 *              .POST(this::createUser))
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .path("/user", builder -> builder.GET(this::listUsers).POST(this::createUser))
+		 *         .build();
 		 * 
* @param pattern the pattern to match to * @param builderConsumer consumer for a {@code Builder} that provides the nested router @@ -816,30 +877,34 @@ public abstract class RouterFunctions { Builder path(String pattern, Consumer builderConsumer); /** - * Filters all routes created by this builder with the given filter function. Filter - * functions are typically used to address cross-cutting concerns, such as logging, - * security, etc. - *

For instance, the following example creates a filter that returns a 401 Unauthorized - * response if the request does not contain the necessary authentication headers. + * Filters all routes created by this builder with the given filter + * function. Filter functions are typically used to address cross-cutting + * concerns, such as logging, security, etc. + *

For instance, the below creates a filter that returns a 401 + * Unauthorized response if the request does not contain the necessary + * authentication headers: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .filter((request, next) -> {
-		 *       // check for authentication headers
-		 *       if (isAuthenticated(request)) {
-		 *         return next.handle(request);
-		 *       }
-		 *       else {
-		 *         return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
-		 *       }
-		 *     })
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .filter((request, next) -> {
+		 *             // check for authentication headers
+		 *             if (isAuthenticated(request)) {
+		 *                 return next.handle(request);
+		 *             }
+		 *             else {
+		 *                 return ServerResponse.status(HttpStatus.UNAUTHORIZED).build();
+		 *             }
+		 *         })
+		 *         .build();
 		 * 
* @param filterFunction the function to filter all routes built by this builder + * @param the type of the {@linkplain HandlerFunction handler function} to filter + * @param the type of the response returned by the function * @return this builder */ - Builder filter(HandlerFilterFunction filterFunction); + Builder filter( + HandlerFilterFunction filterFunction); /** * Filter the request object for all routes created by this builder with the given request @@ -863,68 +928,75 @@ public abstract class RouterFunctions { Builder before(Function requestProcessor); /** - * Filter the response object for all routes created by this builder with the given response - * processing function. Filters are typically used to address cross-cutting concerns, such - * as logging, security, etc. - *

For instance, the following example creates a filter that logs the response after - * the handler function executes. + * Filter the response object for all routes created by this builder + * with the given response processing function. Filters are typically + * used to address cross-cutting concerns, such as logging, security, etc. + *

For instance, the following example creates a filter that logs + * the response after the handler function executes: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .after((request, response) -> {
-		 *       log(response);
-		 *       return response;
-		 *     })
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .after((request, response) -> {
+		 *             log(response);
+		 *             return response;
+		 *         })
+		 *         .build();
 		 * 
* @param responseProcessor a function that transforms the response + * @param the type of the {@linkplain HandlerFunction handler function} to filter + * @param the type of the response returned by the function * @return this builder */ - Builder after(BiFunction responseProcessor); + Builder after( + BiFunction responseProcessor); /** - * Filters all exceptions that match the predicate by applying the given response provider - * function. - *

For instance, the following example creates a filter that returns a 500 response - * status when an {@code IllegalStateException} occurs. + * Filters all exceptions that match the predicate by applying the given + * response provider function. + *

For instance, the following example creates a filter that returns + * a 500 response status when an {@code IllegalStateException} occurs: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .onError(e -> e instanceof IllegalStateException,
-		 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .onError(e -> e instanceof IllegalStateException,
+		 *             (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
+		 *         .build();
 		 * 
* @param predicate the type of exception to filter * @param responseProvider a function that creates a response + * @param the type of response returned by the handler function * @return this builder */ - Builder onError(Predicate predicate, - BiFunction responseProvider); + Builder onError( + Predicate predicate, BiFunction responseProvider); /** - * Filters all exceptions of the given type by applying the given response provider - * function. - *

For instance, the following example creates a filter that returns a 500 response - * status when an {@code IllegalStateException} occurs. + * Filters all exceptions of the given type by applying the given + * response provider function. + *

For instance, the following example creates a filter that returns + * a 500 response status when an {@code IllegalStateException} occurs: *

 		 * RouterFunction<ServerResponse> filteredRoute =
-		 *   RouterFunctions.route()
-		 *     .GET("/user", this::listUsers)
-		 *     .onError(IllegalStateException.class,
-		 *       (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
-		 *     .build();
+		 *     RouterFunctions.route()
+		 *         .GET("/user", this::listUsers)
+		 *         .onError(IllegalStateException.class,
+		 *             (e, request) -> ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).build())
+		 *         .build();
 		 * 
* @param exceptionType the type of exception to filter * @param responseProvider a function that creates a response + * @param the type of response returned by the handler function * @return this builder */ - Builder onError(Class exceptionType, + Builder onError( + Class exceptionType, BiFunction responseProvider); /** - * Add an attribute with the given name and value to the last route built with this builder. + * Add an attribute with the given name and value to the last route + * built with this builder. * @param name the attribute name * @param value the attribute value * @return this builder @@ -933,11 +1005,11 @@ public abstract class RouterFunctions { Builder withAttribute(String name, Object value); /** - * Manipulate the attributes of the last route built with the given consumer. - *

The map provided to the consumer is "live", so that the consumer can be used - * to {@linkplain Map#put(Object, Object) overwrite} existing attributes, - * {@linkplain Map#remove(Object) remove} attributes, or use any of the other - * {@link Map} methods. + * Manipulate the attributes of the last route built. + *

The map provided to the consumer is "live", so that the consumer + * can be used to {@linkplain Map#put(Object, Object) overwrite} existing + * attributes, {@linkplain Map#remove(Object) remove} attributes, or use + * any of the other {@link Map} methods. * @param attributesConsumer a function that consumes the attributes map * @return this builder * @since 5.3 @@ -946,8 +1018,8 @@ public abstract class RouterFunctions { /** * Builds the {@code RouterFunction}. All created routes are - * {@linkplain RouterFunction#and(RouterFunction) composed} with one another, and filters - * (if any) are applied to the result. + * {@linkplain RouterFunction#and(RouterFunction) composed} with one + * another, and filters (if any) are applied to the result. * @return the built router function */ RouterFunction build(); @@ -997,8 +1069,9 @@ public abstract class RouterFunctions { void attributes(Map attributes); /** - * Receive notification of an unknown router function. This method is called for router - * functions that were not created via the various {@link RouterFunctions} methods. + * Receive notification of an unknown router function. + * This method is called for router functions that were not created via + * the various {@link RouterFunctions} methods. * @param routerFunction the router function */ void unknown(RouterFunction routerFunction); @@ -1017,9 +1090,9 @@ public abstract class RouterFunctions { /** - * A composed routing function that first invokes one function, and then invokes the - * another function (of the same response type {@code T}) if this route had - * {@linkplain Optional#empty() no result}. + * A composed routing function that first invokes one function, and then + * invokes another function (of the same response type {@code T}) if this + * route had {@linkplain Optional#empty() no result}. * @param the server response type */ static final class SameComposedRouterFunction extends AbstractRouterFunction { @@ -1053,9 +1126,9 @@ public abstract class RouterFunctions { /** - * A composed routing function that first invokes one function, and then invokes - * another function (of a different response type) if this route had - * {@linkplain Optional#empty() no result}. + * A composed routing function that first invokes one function, + * and then invokes another function (of a different response type) + * if this route had {@linkplain Optional#empty() no result}. */ static final class DifferentComposedRouterFunction extends AbstractRouterFunction { @@ -1090,8 +1163,8 @@ public abstract class RouterFunctions { /** - * Filter the specified {@linkplain HandlerFunction handler functions} with the given - * {@linkplain HandlerFilterFunction filter function}. + * Filter the specified {@linkplain HandlerFunction handler functions} + * with the given {@linkplain HandlerFilterFunction filter function}. * @param the type of the {@linkplain HandlerFunction handler function} to filter * @param the type of the response of the function */ @@ -1103,8 +1176,8 @@ public abstract class RouterFunctions { private final HandlerFilterFunction filterFunction; public FilteredRouterFunction( - RouterFunction routerFunction, - HandlerFilterFunction filterFunction) { + RouterFunction routerFunction, HandlerFilterFunction filterFunction) { + this.routerFunction = routerFunction; this.filterFunction = filterFunction; } @@ -1165,34 +1238,34 @@ public abstract class RouterFunctions { private final RouterFunction routerFunction; - public DefaultNestedRouterFunction(RequestPredicate predicate, RouterFunction routerFunction) { + public DefaultNestedRouterFunction(RequestPredicate predicate, RouterFunction function) { Assert.notNull(predicate, "Predicate must not be null"); - Assert.notNull(routerFunction, "RouterFunction must not be null"); + Assert.notNull(function, "RouterFunction must not be null"); this.predicate = predicate; - this.routerFunction = routerFunction; + this.routerFunction = function; } @Override public Optional> route(ServerRequest serverRequest) { return this.predicate.nest(serverRequest) .map(nestedRequest -> { - if (logger.isTraceEnabled()) { - logger.trace(String.format("Nested predicate \"%s\" matches against \"%s\"", - this.predicate, serverRequest)); - } - Optional> result = this.routerFunction.route(nestedRequest); - if (result.isPresent() && nestedRequest != serverRequest) { - // new attributes map from nestedRequest.attributes() can be composed of the old attributes, - // which means that clearing the old attributes will remove those values from new attributes as well - // so let's make a copy - Map newAttributes = new LinkedHashMap<>(nestedRequest.attributes()); - Map oldAttributes = serverRequest.attributes(); - oldAttributes.clear(); - oldAttributes.putAll(newAttributes); - } - return result; - } - ) + if (logger.isTraceEnabled()) { + logger.trace(String.format("Nested predicate \"%s\" matches against \"%s\"", + this.predicate, serverRequest)); + } + Optional> result = this.routerFunction.route(nestedRequest); + if (result.isPresent() && nestedRequest != serverRequest) { + // new attributes map from nestedRequest.attributes() can be composed of + // the old attributes, which means clearing the old attributes will remove + // those values from new attributes as well + // so let's make a copy + Map newAttributes = new LinkedHashMap<>(nestedRequest.attributes()); + Map oldAttributes = serverRequest.attributes(); + oldAttributes.clear(); + oldAttributes.putAll(newAttributes); + } + return result; + }) .orElseGet(Optional::empty); } @@ -1212,7 +1285,8 @@ public abstract class RouterFunctions { private final BiConsumer headersConsumer; - public ResourcesRouterFunction(Function> lookupFunction, + public ResourcesRouterFunction( + Function> lookupFunction, BiConsumer headersConsumer) { Assert.notNull(lookupFunction, "Lookup function must not be null"); @@ -1223,7 +1297,8 @@ public abstract class RouterFunctions { @Override public Optional> route(ServerRequest request) { - return this.lookupFunction.apply(request).map(resource -> new ResourceHandlerFunction(resource, this.headersConsumer)); + return this.lookupFunction.apply(request) + .map(resource -> new ResourceHandlerFunction(resource, this.headersConsumer)); } @Override @@ -1245,12 +1320,8 @@ public abstract class RouterFunctions { } private static Map initAttributes(Map attributes) { - if (attributes.isEmpty()) { - return Collections.emptyMap(); - } - else { - return Collections.unmodifiableMap(new LinkedHashMap<>(attributes)); - } + return (attributes.isEmpty() ? + Collections.emptyMap() : Collections.unmodifiableMap(new LinkedHashMap<>(attributes))); } @Override