Browse Source

Support for direct path lookups in WebFlux

Closes gh-22961
pull/25381/head
Rossen Stoyanchev 4 years ago
parent
commit
0584c289ab
  1. 35
      spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/PatternsRequestCondition.java
  2. 66
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java
  3. 8
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java
  4. 5
      spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java
  5. 47
      spring-webflux/src/test/java/org/springframework/web/reactive/result/method/HandlerMethodMappingTests.java
  6. 54
      spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
  7. 45
      spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java

35
spring-webflux/src/main/java/org/springframework/web/reactive/result/condition/PatternsRequestCondition.java

@ -19,6 +19,7 @@ package org.springframework.web.reactive.result.condition; @@ -19,6 +19,7 @@ package org.springframework.web.reactive.result.condition;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
@ -45,6 +46,8 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat @@ -45,6 +46,8 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
private static final SortedSet<PathPattern> EMPTY_PATH_PATTERN =
new TreeSet<>(Collections.singleton(PathPatternParser.defaultInstance.parse("")));
private static final Set<String> EMPTY_PATH = Collections.singleton("");
private final SortedSet<PathPattern> patterns;
@ -83,6 +86,28 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat @@ -83,6 +86,28 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
return " || ";
}
private boolean isEmptyPathMapping() {
return this.patterns == EMPTY_PATH_PATTERN;
}
/**
* Return the mapping paths that are not patterns.
* @since 5.3
*/
public Set<String> getDirectPaths() {
if (isEmptyPathMapping()) {
return EMPTY_PATH;
}
Set<String> result = Collections.emptySet();
for (PathPattern pattern : this.patterns) {
if (!pattern.hasPatternSyntax()) {
result = (result.isEmpty() ? new HashSet<>(1) : result);
result.add(pattern.getPatternString());
}
}
return result;
}
/**
* Returns a new instance with URL patterns from the current instance ("this") and
* the "other" instance as follows:
@ -95,13 +120,13 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat @@ -95,13 +120,13 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
*/
@Override
public PatternsRequestCondition combine(PatternsRequestCondition other) {
if (isEmptyPathPattern() && other.isEmptyPathPattern()) {
if (isEmptyPathMapping() && other.isEmptyPathMapping()) {
return this;
}
else if (other.isEmptyPathPattern()) {
else if (other.isEmptyPathMapping()) {
return this;
}
else if (isEmptyPathPattern()) {
else if (isEmptyPathMapping()) {
return other;
}
else {
@ -115,10 +140,6 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat @@ -115,10 +140,6 @@ public final class PatternsRequestCondition extends AbstractRequestCondition<Pat
}
}
private boolean isEmptyPathPattern() {
return this.patterns == EMPTY_PATH_PATTERN;
}
/**
* Checks if any of the patterns match the given request and returns an instance
* that is guaranteed to contain matching patterns, sorted.

66
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/AbstractHandlerMethodMapping.java

@ -41,6 +41,8 @@ import org.springframework.http.server.RequestPath; @@ -41,6 +41,8 @@ import org.springframework.http.server.RequestPath;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.method.HandlerMethod;
@ -311,8 +313,13 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -311,8 +313,13 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
@Nullable
protected HandlerMethod lookupHandlerMethod(ServerWebExchange exchange) throws Exception {
List<Match> matches = new ArrayList<>();
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, exchange);
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(exchange);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, exchange);
}
if (matches.isEmpty()) {
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, exchange);
}
if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(exchange));
matches.sort(comparator);
@ -412,6 +419,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -412,6 +419,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
@Nullable
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
/**
* Return the request mapping paths that are not patterns.
* @since 5.3
*/
protected Set<String> getDirectPaths(T mapping) {
return Collections.emptySet();
}
/**
* Check if a mapping matches the current request and return a (potentially
* new) mapping with conditions relevant to the current request.
@ -443,6 +458,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -443,6 +458,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
private final Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
@ -455,6 +472,17 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -455,6 +472,17 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
return this.mappingLookup;
}
/**
* Return matches for the given URL path. Not thread-safe.
* @since 5.3
* @see #acquireReadLock()
*/
@Nullable
public List<T> getMappingsByDirectPath(ServerWebExchange exchange) {
String path = exchange.getRequest().getPath().pathWithinApplication().value();
return this.pathLookup.get(path);
}
/**
* Return CORS configuration. Thread-safe for concurrent use.
*/
@ -485,13 +513,18 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -485,13 +513,18 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
validateMethodMapping(handlerMethod, mapping);
this.mappingLookup.put(mapping, handlerMethod);
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
CorsConfiguration config = initCorsConfiguration(handler, method, mapping);
if (config != null) {
config.validateAllowCredentials();
this.corsLookup.put(handlerMethod, config);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod));
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths));
}
finally {
this.readWriteLock.writeLock().unlock();
@ -512,13 +545,24 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -512,13 +545,24 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
public void unregister(T mapping) {
this.readWriteLock.writeLock().lock();
try {
MappingRegistration<T> definition = this.registry.remove(mapping);
if (definition == null) {
MappingRegistration<T> registration = this.registry.remove(mapping);
if (registration == null) {
return;
}
this.mappingLookup.remove(definition.getMapping());
this.corsLookup.remove(definition.getHandlerMethod());
this.mappingLookup.remove(registration.getMapping());
for (String path : registration.getDirectPaths()) {
List<T> mappings = this.pathLookup.get(path);
if (mappings != null) {
mappings.remove(registration.getMapping());
if (mappings.isEmpty()) {
this.pathLookup.remove(path);
}
}
}
this.corsLookup.remove(registration.getHandlerMethod());
}
finally {
this.readWriteLock.writeLock().unlock();
@ -533,11 +577,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -533,11 +577,14 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private final HandlerMethod handlerMethod;
public MappingRegistration(T mapping, HandlerMethod handlerMethod) {
private final Set<String> directPaths;
public MappingRegistration(T mapping, HandlerMethod handlerMethod, @Nullable Set<String> directPaths) {
Assert.notNull(mapping, "Mapping must not be null");
Assert.notNull(handlerMethod, "HandlerMethod must not be null");
this.mapping = mapping;
this.handlerMethod = handlerMethod;
this.directPaths = (directPaths != null ? directPaths : Collections.emptySet());
}
public T getMapping() {
@ -548,6 +595,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -548,6 +595,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
return this.handlerMethod;
}
public Set<String> getDirectPaths() {
return this.directPaths;
}
}

8
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfo.java

@ -145,6 +145,14 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping @@ -145,6 +145,14 @@ public final class RequestMappingInfo implements RequestCondition<RequestMapping
return this.patternsCondition;
}
/**
* Return the mapping paths that are not patterns.
* @since 5.3
*/
public Set<String> getDirectPaths() {
return this.patternsCondition.getDirectPaths();
}
/**
* Returns the HTTP request methods of this {@link RequestMappingInfo};
* or instance with 0 request methods, never {@code null}.

5
spring-webflux/src/main/java/org/springframework/web/reactive/result/method/RequestMappingInfoHandlerMapping.java

@ -71,6 +71,11 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe @@ -71,6 +71,11 @@ public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMe
}
@Override
protected Set<String> getDirectPaths(RequestMappingInfo info) {
return info.getDirectPaths();
}
/**
* Check if the given RequestMappingInfo matches the current request and
* return a (potentially new) instance with conditions that match the

47
spring-webflux/src/test/java/org/springframework/web/reactive/result/method/HandlerMethodMappingTests.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,7 +17,11 @@ @@ -17,7 +17,11 @@
package org.springframework.web.reactive.result.method;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -45,7 +49,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; @@ -45,7 +49,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
*/
public class HandlerMethodMappingTests {
private AbstractHandlerMethodMapping<String> mapping;
private MyHandlerMethodMapping mapping;
private MyHandler handler;
@ -71,17 +75,18 @@ public class HandlerMethodMappingTests { @@ -71,17 +75,18 @@ public class HandlerMethodMappingTests {
}
@Test
public void directMatch() throws Exception {
String key = "foo";
this.mapping.registerMapping(key, this.handler, this.method1);
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get(key));
public void directMatch() {
this.mapping.registerMapping("/foo", this.handler, this.method1);
this.mapping.registerMapping("/fo*", this.handler, this.method2);
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/foo"));
Mono<Object> result = this.mapping.getHandler(exchange);
assertThat(((HandlerMethod) result.block()).getMethod()).isEqualTo(this.method1);
assertThat(this.mapping.getMatches()).containsExactly("/foo");
}
@Test
public void patternMatch() throws Exception {
public void patternMatch() {
this.mapping.registerMapping("/fo*", this.handler, this.method1);
this.mapping.registerMapping("/f*", this.handler, this.method2);
@ -91,7 +96,7 @@ public class HandlerMethodMappingTests { @@ -91,7 +96,7 @@ public class HandlerMethodMappingTests {
}
@Test
public void ambiguousMatch() throws Exception {
public void ambiguousMatch() {
this.mapping.registerMapping("/f?o", this.handler, this.method1);
this.mapping.registerMapping("/fo?", this.handler, this.method2);
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/foo"));
@ -101,7 +106,7 @@ public class HandlerMethodMappingTests { @@ -101,7 +106,7 @@ public class HandlerMethodMappingTests {
}
@Test
public void registerMapping() throws Exception {
public void registerMapping() {
String key1 = "/foo";
String key2 = "/foo*";
this.mapping.registerMapping(key1, this.handler, this.method1);
@ -112,7 +117,7 @@ public class HandlerMethodMappingTests { @@ -112,7 +117,7 @@ public class HandlerMethodMappingTests {
}
@Test
public void registerMappingWithSameMethodAndTwoHandlerInstances() throws Exception {
public void registerMappingWithSameMethodAndTwoHandlerInstances() {
String key1 = "foo";
String key2 = "bar";
MyHandler handler1 = new MyHandler();
@ -125,7 +130,7 @@ public class HandlerMethodMappingTests { @@ -125,7 +130,7 @@ public class HandlerMethodMappingTests {
}
@Test
public void unregisterMapping() throws Exception {
public void unregisterMapping() {
String key = "foo";
this.mapping.registerMapping(key, this.handler, this.method1);
Mono<Object> result = this.mapping.getHandler(MockServerWebExchange.from(MockServerHttpRequest.get(key)));
@ -144,6 +149,13 @@ public class HandlerMethodMappingTests { @@ -144,6 +149,13 @@ public class HandlerMethodMappingTests {
private PathPatternParser parser = new PathPatternParser();
private final List<String> matches = new ArrayList<>();
public List<String> getMatches() {
return this.matches;
}
@Override
protected boolean isHandler(Class<?> beanType) {
return true;
@ -155,18 +167,27 @@ public class HandlerMethodMappingTests { @@ -155,18 +167,27 @@ public class HandlerMethodMappingTests {
return methodName.startsWith("handler") ? methodName : null;
}
@Override
protected Set<String> getDirectPaths(String mapping) {
return (parser.parse(mapping).hasPatternSyntax() ?
Collections.emptySet() : Collections.singleton(mapping));
}
@Override
protected String getMatchingMapping(String pattern, ServerWebExchange exchange) {
PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
PathPattern parsedPattern = this.parser.parse(pattern);
return (parsedPattern.matches(lookupPath) ? pattern : null);
String match = parsedPattern.matches(lookupPath) ? pattern : null;
if (match != null) {
matches.add(match);
}
return match;
}
@Override
protected Comparator<String> getMappingComparator(ServerWebExchange exchange) {
return (o1, o2) -> PathPattern.SPECIFICITY_COMPARATOR.compare(parser.parse(o1), parser.parse(o2));
}
}
@Controller

54
spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java

@ -381,15 +381,13 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -381,15 +381,13 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
@ -503,7 +501,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -503,7 +501,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
* {@link #getDirectPaths(Object)} instead
*/
@Deprecated
protected abstract Set<String> getMappingPathPatterns(T mapping);
protected Set<String> getMappingPathPatterns(T mapping) {
return Collections.emptySet();
}
/**
* Return the request mapping paths that are not patterns.
@ -550,7 +550,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -550,7 +550,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
private final MultiValueMap<String, T> pathLookup = new LinkedMultiValueMap<>();
private final Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
@ -571,8 +571,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -571,8 +571,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
* @see #acquireReadLock()
*/
@Nullable
public List<T> getMappingsByUrl(String urlPath) {
return this.urlLookup.get(urlPath);
public List<T> getMappingsByDirectPath(String urlPath) {
return this.pathLookup.get(urlPath);
}
/**
@ -619,9 +619,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -619,9 +619,9 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
validateMethodMapping(handlerMethod, mapping);
this.mappingLookup.put(mapping, handlerMethod);
Set<String> directUrls = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
for (String url : directUrls) {
this.urlLookup.add(url, mapping);
Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
for (String path : directPaths) {
this.pathLookup.add(path, mapping);
}
String name = null;
@ -636,7 +636,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -636,7 +636,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
this.corsLookup.put(handlerMethod, config);
}
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directPaths, name));
}
finally {
this.readWriteLock.writeLock().unlock();
@ -675,26 +675,26 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -675,26 +675,26 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
public void unregister(T mapping) {
this.readWriteLock.writeLock().lock();
try {
MappingRegistration<T> definition = this.registry.remove(mapping);
if (definition == null) {
MappingRegistration<T> registration = this.registry.remove(mapping);
if (registration == null) {
return;
}
this.mappingLookup.remove(definition.getMapping());
this.mappingLookup.remove(registration.getMapping());
for (String url : definition.getDirectUrls()) {
List<T> list = this.urlLookup.get(url);
if (list != null) {
list.remove(definition.getMapping());
if (list.isEmpty()) {
this.urlLookup.remove(url);
for (String path : registration.getDirectPaths()) {
List<T> mappings = this.pathLookup.get(path);
if (mappings != null) {
mappings.remove(registration.getMapping());
if (mappings.isEmpty()) {
this.pathLookup.remove(path);
}
}
}
removeMappingName(definition);
removeMappingName(registration);
this.corsLookup.remove(definition.getHandlerMethod());
this.corsLookup.remove(registration.getHandlerMethod());
}
finally {
this.readWriteLock.writeLock().unlock();
@ -732,19 +732,19 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -732,19 +732,19 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
private final HandlerMethod handlerMethod;
private final Set<String> directUrls;
private final Set<String> directPaths;
@Nullable
private final String mappingName;
public MappingRegistration(T mapping, HandlerMethod handlerMethod,
@Nullable Set<String> directUrls, @Nullable String mappingName) {
@Nullable Set<String> directPaths, @Nullable String mappingName) {
Assert.notNull(mapping, "Mapping must not be null");
Assert.notNull(handlerMethod, "HandlerMethod must not be null");
this.mapping = mapping;
this.handlerMethod = handlerMethod;
this.directUrls = (directUrls != null ? directUrls : Collections.emptySet());
this.directPaths = (directPaths != null ? directPaths : Collections.emptySet());
this.mappingName = mappingName;
}
@ -756,8 +756,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap @@ -756,8 +756,8 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
return this.handlerMethod;
}
public Set<String> getDirectUrls() {
return this.directUrls;
public Set<String> getDirectPaths() {
return this.directPaths;
}
@Nullable

45
spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.web.servlet.handler;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -51,7 +52,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; @@ -51,7 +52,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@SuppressWarnings("unused")
public class HandlerMethodMappingTests {
private AbstractHandlerMethodMapping<String> mapping;
private MyHandlerMethodMapping mapping;
private MyHandler handler;
@ -78,13 +79,15 @@ public class HandlerMethodMappingTests { @@ -78,13 +79,15 @@ public class HandlerMethodMappingTests {
@Test
public void directMatch() throws Exception {
String key = "foo";
this.mapping.registerMapping(key, this.handler, this.method1);
this.mapping.registerMapping("/foo", this.handler, this.method1);
this.mapping.registerMapping("/fo*", this.handler, this.method2);
MockHttpServletRequest request = new MockHttpServletRequest("GET", key);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
HandlerMethod result = this.mapping.getHandlerInternal(request);
assertThat(result.getMethod()).isEqualTo(method1);
assertThat(request.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE)).isEqualTo(result);
assertThat(this.mapping.getMatches()).containsExactly("/foo");
}
@Test
@ -99,7 +102,7 @@ public class HandlerMethodMappingTests { @@ -99,7 +102,7 @@ public class HandlerMethodMappingTests {
}
@Test
public void ambiguousMatch() throws Exception {
public void ambiguousMatch() {
this.mapping.registerMapping("/f?o", this.handler, this.method1);
this.mapping.registerMapping("/fo?", this.handler, this.method2);
@ -127,7 +130,7 @@ public class HandlerMethodMappingTests { @@ -127,7 +130,7 @@ public class HandlerMethodMappingTests {
}
@Test
public void registerMapping() throws Exception {
public void registerMapping() {
String key1 = "/foo";
String key2 = "/foo*";
@ -136,7 +139,7 @@ public class HandlerMethodMappingTests { @@ -136,7 +139,7 @@ public class HandlerMethodMappingTests {
// Direct URL lookup
List<String> directUrlMatches = this.mapping.getMappingRegistry().getMappingsByUrl(key1);
List<String> directUrlMatches = this.mapping.getMappingRegistry().getMappingsByDirectPath(key1);
assertThat(directUrlMatches).isNotNull();
assertThat(directUrlMatches.size()).isEqualTo(1);
assertThat(directUrlMatches.get(0)).isEqualTo(key1);
@ -170,7 +173,7 @@ public class HandlerMethodMappingTests { @@ -170,7 +173,7 @@ public class HandlerMethodMappingTests {
}
@Test
public void registerMappingWithSameMethodAndTwoHandlerInstances() throws Exception {
public void registerMappingWithSameMethodAndTwoHandlerInstances() {
String key1 = "foo";
String key2 = "bar";
@ -186,7 +189,7 @@ public class HandlerMethodMappingTests { @@ -186,7 +189,7 @@ public class HandlerMethodMappingTests {
// Direct URL lookup
List<String> directUrlMatches = this.mapping.getMappingRegistry().getMappingsByUrl(key1);
List<String> directUrlMatches = this.mapping.getMappingRegistry().getMappingsByDirectPath(key1);
assertThat(directUrlMatches).isNotNull();
assertThat(directUrlMatches.size()).isEqualTo(1);
assertThat(directUrlMatches.get(0)).isEqualTo(key1);
@ -222,7 +225,7 @@ public class HandlerMethodMappingTests { @@ -222,7 +225,7 @@ public class HandlerMethodMappingTests {
this.mapping.unregisterMapping(key);
assertThat(mapping.getHandlerInternal(new MockHttpServletRequest("GET", key))).isNull();
assertThat(this.mapping.getMappingRegistry().getMappingsByUrl(key)).isNull();
assertThat(this.mapping.getMappingRegistry().getMappingsByDirectPath(key)).isNull();
assertThat(this.mapping.getMappingRegistry().getHandlerMethodsByMappingName(this.method1.getName())).isNull();
assertThat(this.mapping.getMappingRegistry().getCorsConfiguration(handlerMethod)).isNull();
}
@ -253,26 +256,30 @@ public class HandlerMethodMappingTests { @@ -253,26 +256,30 @@ public class HandlerMethodMappingTests {
private PathMatcher pathMatcher = new AntPathMatcher();
private final List<String> matches = new ArrayList<>();
public MyHandlerMethodMapping() {
setHandlerMethodMappingNamingStrategy(new SimpleMappingNamingStrategy());
}
public List<String> getMatches() {
return this.matches;
}
@Override
protected boolean isHandler(Class<?> beanType) {
return true;
}
@Override
protected String getMappingForMethod(Method method, Class<?> handlerType) {
String methodName = method.getName();
return methodName.startsWith("handler") ? methodName : null;
protected Set<String> getDirectPaths(String mapping) {
return (pathMatcher.isPattern(mapping) ? Collections.emptySet() : Collections.singleton(mapping));
}
@Override
@SuppressWarnings("deprecation")
protected Set<String> getMappingPathPatterns(String key) {
return (this.pathMatcher.isPattern(key) ? Collections.<String>emptySet() : Collections.singleton(key));
protected String getMappingForMethod(Method method, Class<?> handlerType) {
String methodName = method.getName();
return methodName.startsWith("handler") ? methodName : null;
}
@Override
@ -285,7 +292,11 @@ public class HandlerMethodMappingTests { @@ -285,7 +292,11 @@ public class HandlerMethodMappingTests {
@Override
protected String getMatchingMapping(String pattern, HttpServletRequest request) {
String lookupPath = this.pathHelper.getLookupPathForRequest(request);
return this.pathMatcher.match(pattern, lookupPath) ? pattern : null;
String match = (this.pathMatcher.match(pattern, lookupPath) ? pattern : null);
if (match != null) {
this.matches.add(match);
}
return match;
}
@Override

Loading…
Cancel
Save