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 1a6b198617b..8b241efbd6c 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 @@ -16,6 +16,8 @@ package org.springframework.web.reactive.function.server; +import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -460,12 +462,28 @@ public abstract class RouterFunctions { "Nested predicate \"%s\" matches against \"%s\"", this.predicate, serverRequest)); } - return this.routerFunction.route(nestedRequest); + return this.routerFunction.route(nestedRequest) + .doOnNext(match -> { + mergeTemplateVariables(serverRequest, nestedRequest.pathVariables()); + }); } ) .orElseGet(Mono::empty); } + @SuppressWarnings("unchecked") + private void mergeTemplateVariables(ServerRequest request, Map variables) { + if (!variables.isEmpty()) { + Map attributes = request.attributes(); + Map oldVariables = (Map)request.attribute(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE) + .orElseGet(LinkedHashMap::new); + Map mergedVariables = new LinkedHashMap<>(oldVariables); + mergedVariables.putAll(variables); + attributes.put(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE, + Collections.unmodifiableMap(mergedVariables)); + } + } + @Override public void accept(Visitor visitor) { visitor.startNested(this.predicate); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/NestedRouteIntegrationTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/NestedRouteIntegrationTests.java index 087d5430d54..04c1087c469 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/NestedRouteIntegrationTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/function/server/NestedRouteIntegrationTests.java @@ -41,11 +41,12 @@ public class NestedRouteIntegrationTests extends AbstractRouterFunctionIntegrati protected RouterFunction routerFunction() { NestedHandler nestedHandler = new NestedHandler(); return nest(path("/foo/"), - route(GET("/bar"), nestedHandler::bar) - .andRoute(GET("/baz"), nestedHandler::baz)) - .andNest(GET("/{foo}"), - nest(GET("/{bar}"), - route(GET("/{baz}"), nestedHandler::variables))) + route(GET("/bar"), nestedHandler::bar) + .andRoute(GET("/baz"), nestedHandler::baz)) + .andNest(GET("/{foo}"), + route(GET("/bar"), nestedHandler::variables).and( + nest(GET("/{bar}"), + route(GET("/{baz}"), nestedHandler::variables)))) .andRoute(GET("/{qux}/quux"), nestedHandler::variables); } @@ -77,6 +78,17 @@ public class NestedRouteIntegrationTests extends AbstractRouterFunctionIntegrati assertEquals("{foo=1, bar=2, baz=3}", result.getBody()); } + // SPR-16868 + @Test + public void parentVariables() throws Exception { + ResponseEntity result = + restTemplate.getForEntity("http://localhost:" + port + "/1/bar", String.class); + + assertEquals(HttpStatus.OK, result.getStatusCode()); + assertEquals("{foo=1}", result.getBody()); + + } + // SPR 16692 @Test public void removeFailedPathVariables() throws Exception {