Skip to content

Commit d303c8a

Browse files
committed
Store PathPattern instead of String in attributes
This commit changes the attributes stored under RouterFunctions.MATCHING_PATTERN_ATTRIBUTE and HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE from a String to a PathPattern, similar to what annotated controllers set. Issue: SPR-17395
1 parent ab8310b commit d303c8a

File tree

5 files changed

+87
-25
lines changed

5 files changed

+87
-25
lines changed

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RequestPredicates.java

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -369,12 +369,9 @@ private static Map<String, String> mergePathVariables(Map<String, String> oldVar
369369
}
370370
}
371371

372-
private static String mergePatterns(@Nullable String oldPattern, String newPattern) {
372+
private static PathPattern mergePatterns(@Nullable PathPattern oldPattern, PathPattern newPattern) {
373373
if (oldPattern != null) {
374-
if (oldPattern.endsWith("/") && newPattern.startsWith("/")) {
375-
oldPattern = oldPattern.substring(0, oldPattern.length() - 1);
376-
}
377-
return oldPattern + newPattern;
374+
return oldPattern.combine(newPattern);
378375
}
379376
else {
380377
return newPattern;
@@ -429,10 +426,9 @@ public PathPatternPredicate(PathPattern pattern) {
429426
public boolean test(ServerRequest request) {
430427
PathContainer pathContainer = request.pathContainer();
431428
PathPattern.PathMatchInfo info = this.pattern.matchAndExtract(pathContainer);
432-
String patternString = this.pattern.getPatternString();
433-
traceMatch("Pattern", patternString, request.path(), info != null);
429+
traceMatch("Pattern", this.pattern.getPatternString(), request.path(), info != null);
434430
if (info != null) {
435-
mergeAttributes(request, info.getUriVariables(), patternString);
431+
mergeAttributes(request, info.getUriVariables(), this.pattern);
436432
return true;
437433
}
438434
else {
@@ -441,21 +437,21 @@ public boolean test(ServerRequest request) {
441437
}
442438

443439
private static void mergeAttributes(ServerRequest request, Map<String, String> variables,
444-
String pattern) {
440+
PathPattern pattern) {
445441
Map<String, String> pathVariables = mergePathVariables(request.pathVariables(), variables);
446442
request.attributes().put(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
447443
Collections.unmodifiableMap(pathVariables));
448444

449445
pattern = mergePatterns(
450-
(String) request.attributes().get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE),
446+
(PathPattern) request.attributes().get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE),
451447
pattern);
452448
request.attributes().put(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE, pattern);
453449
}
454450

455451
@Override
456452
public Optional<ServerRequest> nest(ServerRequest request) {
457453
return Optional.ofNullable(this.pattern.matchStartOfPath(request.pathContainer()))
458-
.map(info -> new SubPathServerRequestWrapper(request, info, this.pattern.getPatternString()));
454+
.map(info -> new SubPathServerRequestWrapper(request, info, this.pattern));
459455
}
460456

461457
@Override
@@ -662,21 +658,21 @@ private static class SubPathServerRequestWrapper implements ServerRequest {
662658
private final Map<String, Object> attributes;
663659

664660
public SubPathServerRequestWrapper(ServerRequest request,
665-
PathPattern.PathRemainingMatchInfo info, String pattern) {
661+
PathPattern.PathRemainingMatchInfo info, PathPattern pattern) {
666662
this.request = request;
667663
this.pathContainer = new SubPathContainer(info.getPathRemaining());
668664
this.attributes = mergeAttributes(request, info.getUriVariables(), pattern);
669665
}
670666

671667
private static Map<String, Object> mergeAttributes(ServerRequest request,
672-
Map<String, String> pathVariables, String pattern) {
668+
Map<String, String> pathVariables, PathPattern pattern) {
673669
Map<String, Object> result = new ConcurrentHashMap<>(request.attributes());
674670

675671
result.put(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE,
676672
mergePathVariables(request.pathVariables(), pathVariables));
677673

678674
pattern = mergePatterns(
679-
(String) request.attributes().get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE),
675+
(PathPattern) request.attributes().get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE),
680676
pattern);
681677
result.put(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE, pattern);
682678
return result;

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/RouterFunctions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public abstract class RouterFunctions {
7171

7272
/**
7373
* Name of the {@link ServerWebExchange#getAttributes() attribute} that
74-
* contains the matching pattern.
74+
* contains the matching pattern, as a {@link org.springframework.web.util.pattern.PathPattern}.
7575
*/
7676
public static final String MATCHING_PATTERN_ATTRIBUTE =
7777
RouterFunctions.class.getName() + ".matchingPattern";

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/RouterFunctionMapping.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.springframework.web.reactive.function.server.ServerRequest;
3535
import org.springframework.web.reactive.handler.AbstractHandlerMapping;
3636
import org.springframework.web.server.ServerWebExchange;
37+
import org.springframework.web.util.pattern.PathPattern;
3738

3839
/**
3940
* {@code HandlerMapping} implementation that supports {@link RouterFunction RouterFunctions}.
@@ -159,8 +160,8 @@ private void setAttributes(Map<String, Object> attributes, ServerRequest serverR
159160
attributes.put(RouterFunctions.REQUEST_ATTRIBUTE, serverRequest);
160161
attributes.put(BEST_MATCHING_HANDLER_ATTRIBUTE, handlerFunction);
161162

162-
String matchingPattern =
163-
(String) attributes.get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE);
163+
PathPattern matchingPattern =
164+
(PathPattern) attributes.get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE);
164165
if (matchingPattern != null) {
165166
attributes.put(BEST_MATCHING_PATTERN_ATTRIBUTE, matchingPattern);
166167
}

spring-webflux/src/test/java/org/springframework/web/reactive/function/server/DispatcherHandlerIntegrationTests.java

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2018 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.web.reactive.function.server;
1818

1919
import java.util.List;
20+
import java.util.Map;
2021

2122
import org.junit.Test;
2223
import reactor.core.publisher.Flux;
@@ -36,12 +37,15 @@
3637
import org.springframework.web.bind.annotation.ResponseBody;
3738
import org.springframework.web.client.RestTemplate;
3839
import org.springframework.web.reactive.DispatcherHandler;
40+
import org.springframework.web.reactive.HandlerMapping;
3941
import org.springframework.web.reactive.config.EnableWebFlux;
4042
import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
43+
import org.springframework.web.util.pattern.PathPattern;
4144

4245
import static org.junit.Assert.*;
43-
import static org.springframework.web.reactive.function.BodyInserters.*;
44-
import static org.springframework.web.reactive.function.server.RouterFunctions.*;
46+
import static org.springframework.web.reactive.function.BodyInserters.fromPublisher;
47+
import static org.springframework.web.reactive.function.server.RouterFunctions.nest;
48+
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
4549

4650
/**
4751
* Tests the use of {@link HandlerFunction} and {@link RouterFunction} in a
@@ -101,6 +105,15 @@ public void controller() {
101105
assertEquals("John", result.getBody().getName());
102106
}
103107

108+
@Test
109+
public void attributes() {
110+
ResponseEntity<String> result =
111+
this.restTemplate
112+
.getForEntity("http://localhost:" + this.port + "/attributes/bar", String.class);
113+
114+
assertEquals(HttpStatus.OK, result.getStatusCode());
115+
}
116+
104117

105118
@EnableWebFlux
106119
@Configuration
@@ -116,6 +129,12 @@ public PersonController personController() {
116129
return new PersonController();
117130
}
118131

132+
@Bean
133+
public AttributesHandler attributesHandler() {
134+
return new AttributesHandler();
135+
}
136+
137+
119138
@Bean
120139
public RouterFunction<EntityResponse<Person>> monoRouterFunction(PersonHandler personHandler) {
121140
return route(RequestPredicates.GET("/mono"), personHandler::mono);
@@ -126,6 +145,12 @@ public RouterFunction<ServerResponse> fluxRouterFunction(PersonHandler personHan
126145
return route(RequestPredicates.GET("/flux"), personHandler::flux);
127146
}
128147

148+
@Bean
149+
public RouterFunction<ServerResponse> attributesRouterFunction(AttributesHandler attributesHandler) {
150+
return nest(RequestPredicates.GET("/attributes"),
151+
route(RequestPredicates.GET("/{foo}"), attributesHandler::attributes));
152+
}
153+
129154
}
130155

131156

@@ -145,8 +170,44 @@ public Mono<ServerResponse> flux(ServerRequest request) {
145170

146171
}
147172

173+
private static class AttributesHandler {
174+
175+
@SuppressWarnings("unchecked")
176+
public Mono<ServerResponse> attributes(ServerRequest request) {
177+
assertTrue(request.attributes().containsKey(RouterFunctions.REQUEST_ATTRIBUTE));
178+
assertTrue(request.attributes()
179+
.containsKey(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE));
180+
181+
Map<String, String> pathVariables =
182+
(Map<String, String>) request.attributes().get(RouterFunctions.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
183+
assertNotNull(pathVariables);
184+
assertEquals(1, pathVariables.size());
185+
assertEquals("bar", pathVariables.get("foo"));
186+
187+
pathVariables =
188+
(Map<String, String>) request.attributes().get(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
189+
assertNotNull(pathVariables);
190+
assertEquals(1, pathVariables.size());
191+
assertEquals("bar", pathVariables.get("foo"));
192+
193+
194+
PathPattern pattern =
195+
(PathPattern) request.attributes().get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE);
196+
assertNotNull(pattern);
197+
assertEquals("/attributes/{foo}", pattern.getPatternString());
198+
199+
pattern = (PathPattern) request.attributes()
200+
.get(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
201+
assertNotNull(pattern);
202+
assertEquals("/attributes/{foo}", pattern.getPatternString());
203+
204+
return ServerResponse.ok().build();
205+
}
206+
207+
}
208+
148209
@Controller
149-
private static class PersonController {
210+
public static class PersonController {
150211

151212
@RequestMapping("/controller")
152213
@ResponseBody

spring-webflux/src/test/java/org/springframework/web/reactive/function/server/NestedRouteIntegrationTests.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import org.springframework.http.HttpMethod;
2626
import org.springframework.http.HttpStatus;
2727
import org.springframework.http.ResponseEntity;
28+
import org.springframework.lang.Nullable;
2829
import org.springframework.web.client.RestTemplate;
30+
import org.springframework.web.util.pattern.PathPattern;
2931

3032
import static org.junit.Assert.*;
3133
import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
@@ -122,7 +124,7 @@ public void removeFailedPathVariablesAnd() {
122124
private static class NestedHandler {
123125

124126
public Mono<ServerResponse> pattern(ServerRequest request) {
125-
String pattern = matchingPattern(request);
127+
String pattern = matchingPattern(request).getPatternString();
126128
return ServerResponse.ok().syncBody(pattern);
127129
}
128130

@@ -134,7 +136,8 @@ public Mono<ServerResponse> variables(ServerRequest request) {
134136
assertTrue( (pathVariables.equals(attributePathVariables))
135137
|| (pathVariables.isEmpty() && (attributePathVariables == null)));
136138

137-
String pattern = matchingPattern(request);
139+
PathPattern pathPattern = matchingPattern(request);
140+
String pattern = pathPattern != null ? pathPattern.getPatternString() : "";
138141
Flux<String> responseBody;
139142
if (!pattern.isEmpty()) {
140143
responseBody = Flux.just(pattern, "\n", pathVariables.toString());
@@ -144,8 +147,9 @@ public Mono<ServerResponse> variables(ServerRequest request) {
144147
return ServerResponse.ok().body(responseBody, String.class);
145148
}
146149

147-
private String matchingPattern(ServerRequest request) {
148-
return (String) request.attributes().getOrDefault(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE, "");
150+
@Nullable
151+
private PathPattern matchingPattern(ServerRequest request) {
152+
return (PathPattern) request.attributes().get(RouterFunctions.MATCHING_PATTERN_ATTRIBUTE);
149153
}
150154

151155
}

0 commit comments

Comments
 (0)