Empty path mapping behaves consistently

An empty path mapping in an @RequestMapping now consistently matches to
empty paths regardless of whether there are both type and method level,
annotations, or method-level only.

Closes gh-22543
This commit is contained in:
Rossen Stoyanchev
2019-04-09 15:03:24 -04:00
parent f839c1f9cd
commit d1f888a7a9
17 changed files with 96 additions and 41 deletions

View File

@@ -16,9 +16,9 @@
package org.springframework.web.reactive.result.condition;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@@ -29,6 +29,7 @@ import org.springframework.http.server.PathContainer;
import org.springframework.lang.Nullable;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* A logical disjunction (' || ') request condition that matches a request
@@ -40,6 +41,10 @@ import org.springframework.web.util.pattern.PathPattern;
*/
public final class PatternsRequestCondition extends AbstractRequestCondition<PatternsRequestCondition> {
private static final SortedSet<PathPattern> EMPTY_PATTERNS =
new TreeSet<>(Collections.singleton(new PathPatternParser().parse("")));
private final SortedSet<PathPattern> patterns;
@@ -55,7 +60,7 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
* Creates a new instance with the given URL patterns.
*/
public PatternsRequestCondition(List<PathPattern> patterns) {
this(new TreeSet<>(patterns));
this(patterns.isEmpty() ? EMPTY_PATTERNS : new TreeSet<>(patterns));
}
@@ -89,8 +94,9 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
*/
@Override
public PatternsRequestCondition combine(PatternsRequestCondition other) {
List<PathPattern> combined = new ArrayList<>();
SortedSet<PathPattern> combined;
if (!this.patterns.isEmpty() && !other.patterns.isEmpty()) {
combined = new TreeSet<>();
for (PathPattern pattern1 : this.patterns) {
for (PathPattern pattern2 : other.patterns) {
combined.add(pattern1.combine(pattern2));
@@ -98,10 +104,13 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
}
}
else if (!this.patterns.isEmpty()) {
combined.addAll(this.patterns);
combined = this.patterns;
}
else if (!other.patterns.isEmpty()) {
combined.addAll(other.patterns);
combined = other.patterns;
}
else {
combined = EMPTY_PATTERNS;
}
return new PatternsRequestCondition(combined);
}

View File

@@ -140,6 +140,19 @@ public class PatternsRequestConditionTests {
assertNull(match);
}
@Test // gh-22543
public void matchWithEmptyPatterns() {
PatternsRequestCondition condition = new PatternsRequestCondition();
assertEquals(new PatternsRequestCondition(this.parser.parse("")), condition);
assertNotNull(condition.getMatchingCondition(MockServerWebExchange.from(get(""))));
assertNull(condition.getMatchingCondition(MockServerWebExchange.from(get("/anything"))));
condition = condition.combine(new PatternsRequestCondition());
assertEquals(new PatternsRequestCondition(this.parser.parse("")), condition);
assertNotNull(condition.getMatchingCondition(MockServerWebExchange.from(get(""))));
assertNull(condition.getMatchingCondition(MockServerWebExchange.from(get("/anything"))));
}
@Test
public void compareToConsistentWithEquals() throws Exception {
PatternsRequestCondition c1 = createPatternsCondition("/foo*");

View File

@@ -34,6 +34,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.reactive.result.method.RequestMappingInfo;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
import org.springframework.web.util.pattern.PatternParseException;
import static java.util.Arrays.asList;
@@ -61,7 +62,8 @@ public class RequestMappingInfoTests {
public void createEmpty() {
RequestMappingInfo info = paths().build();
assertEquals(0, info.getPatternsCondition().getPatterns().size());
PathPattern emptyPattern = (new PathPatternParser()).parse("");
assertEquals(Collections.singleton(emptyPattern), info.getPatternsCondition().getPatterns());
assertEquals(0, info.getMethodsCondition().getMethods().size());
assertEquals(true, info.getConsumesCondition().isEmpty());
assertEquals(true, info.getProducesCondition().isEmpty());

View File

@@ -253,14 +253,12 @@ public class RequestMappingInfoHandlerMappingTests {
assertSame(handlerMethod, mapped);
}
@Test
@Test // gh-22543
public void handleMatchBestMatchingPatternAttributeNoPatternsDefined() {
RequestMappingInfo key = paths().build();
ServerWebExchange exchange = MockServerWebExchange.from(get("/1/2"));
this.handlerMapping.handleMatch(key, handlerMethod, exchange);
PathPattern bestMatch = (PathPattern) exchange.getAttributes().get(BEST_MATCHING_PATTERN_ATTRIBUTE);
assertEquals("/1/2", bestMatch.getPatternString());
ServerWebExchange exchange = MockServerWebExchange.from(get(""));
this.handlerMapping.handleMatch(paths().build(), handlerMethod, exchange);
PathPattern pattern = (PathPattern) exchange.getAttributes().get(BEST_MATCHING_PATTERN_ATTRIBUTE);
assertEquals("", pattern.getPatternString());
}
@Test