diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
index 25c39189209..a1d8ddb6bb5 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
@@ -30,27 +30,18 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.context.ApplicationContextException;
import org.springframework.util.Assert;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.HandlerMethodSelector;
+import org.springframework.web.util.UrlPathHelper;
/**
* Abstract base class for {@link org.springframework.web.servlet.HandlerMapping HandlerMapping} implementations that
* support mapping requests to {@link HandlerMethod}s rather than to handlers.
*
- *
Each {@link HandlerMethod} is registered with a unique key. Subclasses define the key type and how to create it
- * for a given handler method. Keys represent conditions for matching a handler method to a request.
- *
- *
Subclasses must also define how to create a key for an incoming request. The resulting key is used to perform
- * a {@link HandlerMethod} lookup possibly resulting in a direct match. However, when a map lookup is insufficient,
- * the keys of all handler methods are iterated and subclasses are allowed to make an exhaustive check of key
- * conditions against the request.
- *
- *
Since there can be more than one matching key for a request, subclasses must define a comparator for sorting
- * the keys of matching handler methods in order to find the most specific match.
- *
- * @param A unique key for the registration of mapped {@link HandlerMethod}s representing the conditions to
- * match a handler method to a request.
+ * @param Represents a mapping key with conditions for mapping a request to a {@link HandlerMethod}.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
@@ -58,8 +49,52 @@ import org.springframework.web.method.HandlerMethodSelector;
*/
public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMapping {
+ private UrlPathHelper urlPathHelper = new UrlPathHelper();
+
+ private final MultiValueMap urlMap = new LinkedMultiValueMap();
+
private final Map handlerMethods = new LinkedHashMap();
+ /**
+ * Set if URL lookup should always use the full path within the current servlet context. Else, the path within the
+ * current servlet mapping is used if applicable (that is, in the case of a ".../*" servlet mapping in web.xml).
+ * Default is "false".
+ *
+ * @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
+ */
+ public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
+ this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
+ }
+
+ /**
+ * Set if context path and request URI should be URL-decoded. Both are returned undecoded by the Servlet API, in
+ * contrast to the servlet path.
Uses either the request encoding or the default encoding according to the Servlet
+ * spec (ISO-8859-1).
+ *
+ * @see org.springframework.web.util.UrlPathHelper#setUrlDecode
+ */
+ public void setUrlDecode(boolean urlDecode) {
+ this.urlPathHelper.setUrlDecode(urlDecode);
+ }
+
+ /**
+ * Set the UrlPathHelper to use for resolution of lookup paths.
Use this to override the default UrlPathHelper
+ * with a custom subclass, or to share common UrlPathHelper settings across multiple HandlerMappings and
+ * MethodNameResolvers.
+ *
+ */
+ public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
+ Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
+ this.urlPathHelper = urlPathHelper;
+ }
+
+ /**
+ * Return the {@link UrlPathHelper} to use for resolution of lookup paths.
+ */
+ public UrlPathHelper getUrlPathHelper() {
+ return urlPathHelper;
+ }
+
/**
* Calls the initialization of the superclass and detects handlers.
*/
@@ -71,14 +106,12 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
/**
* Register handler methods found in beans of the current ApplicationContext.
- * The actual key determination for a handler is up to the concrete
- * {@link #getKeyForMethod(Method)} implementation. A method in a bean for which no key
- * could be determined is simply not considered a handler method.
- * @see #getKeyForMethod(Method)
+ *
The actual mapping for a handler is up to the concrete {@link #getMappingKeyForMethod(String, Method)}
+ * implementation.
*/
protected void initHandlerMethods() {
if (logger.isDebugEnabled()) {
- logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
+ logger.debug("Looking for request mappings in application context: " + getApplicationContext());
}
for (String beanName : getApplicationContext().getBeanNamesForType(Object.class)) {
if (isHandler(beanName)){
@@ -102,81 +135,79 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
Set methods = HandlerMethodSelector.selectMethods(handlerType, new MethodFilter() {
public boolean matches(Method method) {
- return getKeyForMethod(beanName, method) != null;
+ return getMappingKeyForMethod(beanName, method) != null;
}
});
for (Method method : methods) {
- T key = getKeyForMethod(beanName, method);
HandlerMethod handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
- registerHandlerMethod(key, handlerMethod);
+ T mapping = getMappingKeyForMethod(beanName, method);
+ Set paths = getMappingPaths(mapping);
+ registerHandlerMethod(paths, mapping, handlerMethod);
}
}
/**
- * Provides a lookup key for the given bean method. A method for which no key can be determined is
+ * Provides a mapping key for the given bean method. A method for which no mapping can be determined is
* not considered a handler method.
*
* @param beanName the name of the bean the method belongs to
- * @param method the method to create a key for
- * @return the lookup key, or {@code null} if the method has none
+ * @param method the method to create a mapping for
+ * @return the mapping key, or {@code null} if the method is not mapped
*/
- protected abstract T getKeyForMethod(String beanName, Method method);
+ protected abstract T getMappingKeyForMethod(String beanName, Method method);
/**
- * Registers a {@link HandlerMethod} under the given key.
- *
- * @param key the key to register the method under
+ * Registers a {@link HandlerMethod} with the given mapping.
+ *
+ * @param paths URL paths mapped to this method
+ * @param mappingKey the mapping key for the method
* @param handlerMethod the handler method to register
- * @throws IllegalStateException if another method was already register under the key
+ * @throws IllegalStateException if another method was already register under the same mapping
*/
- protected void registerHandlerMethod(T key, HandlerMethod handlerMethod) {
- Assert.notNull(key, "'key' must not be null");
+ protected void registerHandlerMethod(Set paths, T mappingKey, HandlerMethod handlerMethod) {
+ Assert.notNull(mappingKey, "'mapping' must not be null");
Assert.notNull(handlerMethod, "'handlerMethod' must not be null");
- HandlerMethod mappedHandlerMethod = handlerMethods.get(key);
+ HandlerMethod mappedHandlerMethod = handlerMethods.get(mappingKey);
if (mappedHandlerMethod != null && !mappedHandlerMethod.equals(handlerMethod)) {
throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + handlerMethod.getBean()
- + "' bean method \n" + handlerMethod + "\nto " + key + ": There is already '"
+ + "' bean method \n" + handlerMethod + "\nto " + mappingKey + ": There is already '"
+ mappedHandlerMethod.getBean() + "' bean method\n" + mappedHandlerMethod + " mapped.");
}
- handlerMethods.put(key, handlerMethod);
+ handlerMethods.put(mappingKey, handlerMethod);
if (logger.isInfoEnabled()) {
- logger.info("Mapped \"" + key + "\" onto " + handlerMethod);
+ logger.info("Mapped \"" + mappingKey + "\" onto " + handlerMethod);
+ }
+ for (String path : paths) {
+ urlMap.add(path, mappingKey);
}
}
+ /**
+ * Get the URL paths for the given mapping.
+ */
+ protected abstract Set getMappingPaths(T mappingKey);
+
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
- T key = getKeyForRequest(request);
- if (key == null) {
- return null;
- }
+ String lookupPath = urlPathHelper.getLookupPathForRequest(request);
if (logger.isDebugEnabled()) {
- logger.debug("Looking up handler method with key [" + key + "]");
+ logger.debug("Looking up handler method for path " + lookupPath);
}
- HandlerMethod handlerMethod = lookupHandlerMethod(key, request);
+ HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
if (logger.isDebugEnabled()) {
if (handlerMethod != null) {
logger.debug("Returning handler method [" + handlerMethod + "]");
}
else {
- logger.debug("Did not find handler method for [" + key + "]");
+ logger.debug("Did not find handler method for [" + lookupPath + "]");
}
}
return (handlerMethod != null) ? handlerMethod.createWithResolvedBean() : null;
}
- /**
- * Abstract template method that returns the lookup key for the given HTTP servlet request.
- *
- * @param request the request to look up the key for
- * @return the key, or {@code null} if the request does not have one
- * @throws Exception in case of errors
- */
- protected abstract T getKeyForRequest(HttpServletRequest request) throws Exception;
-
/**
* Looks up the best-matching {@link HandlerMethod} for the given request.
*
@@ -185,119 +216,126 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
* returns the 1st entry, if any. If no matches are found, {@link #handleNoMatch(Set, HttpServletRequest)} is
* invoked.
*
- * @param lookupKey current lookup key
+ * @param lookupPath mapping lookup path within the current servlet mapping if applicable
* @param request the current HTTP servlet request
* @return the best-matching handler method, or {@code null} if there is no match
*/
- protected HandlerMethod lookupHandlerMethod(T lookupKey, HttpServletRequest request) throws Exception {
- if (handlerMethods.containsKey(lookupKey)) {
+ protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
+ List keys = urlMap.get(lookupPath);
+ if (keys == null) {
+ keys = new ArrayList(handlerMethods.keySet());
+ }
+
+ List matches = new ArrayList();
+
+ for (T key : keys) {
+ T match = getMatchingMappingKey(key, lookupPath, request);
+ if (match != null) {
+ matches.add(new Match(match, handlerMethods.get(key)));
+ }
+ }
+
+ if (!matches.isEmpty()) {
+ Comparator comparator = new MatchComparator(getMappingKeyComparator(lookupPath, request));
+ Collections.sort(matches, comparator);
+
if (logger.isTraceEnabled()) {
- logger.trace("Found direct match for [" + lookupKey + "]");
+ logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
- handleMatch(lookupKey, request);
- return handlerMethods.get(lookupKey);
+ Match bestMatch = matches.get(0);
+ if (matches.size() > 1) {
+ Match secondBestMatch = matches.get(1);
+ if (comparator.compare(bestMatch, secondBestMatch) == 0) {
+ Method m1 = bestMatch.handlerMethod.getMethod();
+ Method m2 = secondBestMatch.handlerMethod.getMethod();
+ throw new IllegalStateException(
+ "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
+ m1 + ", " + m2 + "}");
+ }
+ }
+
+ handleMatch(bestMatch.mappingKey, lookupPath, request);
+ return bestMatch.handlerMethod;
}
else {
- List matches = new ArrayList();
-
- for (Map.Entry entry : handlerMethods.entrySet()) {
- T match = getMatchingKey(entry.getKey(), request);
- if (match != null) {
- matches.add(new Match(match, entry.getValue()));
- }
- }
-
- if (!matches.isEmpty()) {
- Comparator comparator = getMatchComparator(request);
- Collections.sort(matches, comparator);
-
- if (logger.isTraceEnabled()) {
- logger.trace("Found " + matches.size() + " matching key(s) for [" + lookupKey + "] : " + matches);
- }
-
- Match bestMatch = matches.get(0);
- if (matches.size() > 1) {
- Match secondBestMatch = matches.get(1);
- if (comparator.compare(bestMatch, secondBestMatch) == 0) {
- Method m1 = bestMatch.handlerMethod.getMethod();
- Method m2 = secondBestMatch.handlerMethod.getMethod();
- throw new IllegalStateException(
- "Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" +
- m1 + ", " + m2 + "}");
- }
- }
-
- handleMatch(bestMatch.key, request);
- return bestMatch.handlerMethod;
- }
- else {
- return handleNoMatch(handlerMethods.keySet(), request);
- }
+ return handleNoMatch(handlerMethods.keySet(), lookupPath, request);
}
}
/**
- * Invoked when a key matching to a request has been identified.
+ * Invoked when a request has been matched to a mapping.
*
- * @param key the key selected for the request returned by {@link #getMatchingKey(Object, HttpServletRequest)}.
+ * @param mappingKey the mapping selected for the request returned by
+ * {@link #getMatchingMappingKey(Object, String, HttpServletRequest)}.
+ * @param lookupPath mapping lookup path within the current servlet mapping if applicable
* @param request the current request
*/
- protected void handleMatch(T key, HttpServletRequest request) {
+ protected void handleMatch(T mappingKey, String lookupPath, HttpServletRequest request) {
}
/**
- * Returns the matching variant of the given key, given the current HTTP servlet request.
+ * Checks if the mapping matches the current request and returns a mapping updated to contain only conditions
+ * relevant to the current request (for example a mapping may have several HTTP methods, the matching mapping
+ * will contain only 1).
*
- * @param key the key to get the matches for
+ * @param mappingKey the mapping key to get a match for
+ * @param lookupPath mapping lookup path within the current servlet mapping if applicable
* @param request the current HTTP servlet request
- * @return the matching key, or {@code null} if the given key does not match against the servlet request
+ * @return a matching mapping, or {@code null} if the given mapping does not match the request
*/
- protected abstract T getMatchingKey(T key, HttpServletRequest request);
-
- private Comparator getMatchComparator(HttpServletRequest request) {
- final Comparator keyComparator = getKeyComparator(request);
- return new Comparator() {
- public int compare(Match m1, Match m2) {
- return keyComparator.compare(m1.key, m2.key);
- }
- };
- }
+ protected abstract T getMatchingMappingKey(T mappingKey, String lookupPath, HttpServletRequest request);
/**
- * Returns a comparator to sort the keys with. The returned comparator should sort 'better' matches higher.
+ * Returns a comparator to sort mapping keys with. The returned comparator should sort 'better' matches higher.
*
+ * @param lookupPath mapping lookup path within the current servlet mapping if applicable
* @param request the current HTTP servlet request
* @return the comparator
*/
- protected abstract Comparator getKeyComparator(HttpServletRequest request);
+ protected abstract Comparator getMappingKeyComparator(String lookupPath, HttpServletRequest request);
/**
* Invoked when no match was found. Default implementation returns {@code null}.
*
- * @param requestKeys the registered request keys
+ * @param mappingKeys all registered mappings
+ * @param lookupPath mapping lookup path within the current servlet mapping if applicable
* @param request the current HTTP request
* @throws ServletException in case of errors
*/
- protected HandlerMethod handleNoMatch(Set requestKeys, HttpServletRequest request) throws Exception {
+ protected HandlerMethod handleNoMatch(Set mappingKeys, String lookupPath, HttpServletRequest request)
+ throws Exception {
return null;
}
private class Match {
- private final T key;
+ private final T mappingKey;
private final HandlerMethod handlerMethod;
- private Match(T key, HandlerMethod handlerMethod) {
- this.key = key;
+ private Match(T mapping, HandlerMethod handlerMethod) {
+ this.mappingKey = mapping;
this.handlerMethod = handlerMethod;
}
@Override
public String toString() {
- return key.toString();
+ return mappingKey.toString();
}
}
-}
+ private class MatchComparator implements Comparator {
+
+ private final Comparator comparator;
+
+ public MatchComparator(Comparator comparator) {
+ this.comparator = comparator;
+ }
+
+ public int compare(Match match1, Match match2) {
+ return comparator.compare(match1.mappingKey, match2.mappingKey);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMapping.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMapping.java
index 5300a6c48c3..aeb1d7e7d91 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMapping.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMapping.java
@@ -17,6 +17,7 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.lang.reflect.Method;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
@@ -42,71 +43,22 @@ import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.handler.MappedInterceptors;
-import org.springframework.web.util.UrlPathHelper;
+import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
/**
- * An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestKey}s for the registration and the lookup
- * of {@link HandlerMethod}s.
- *
- * A {@link RequestKey} for an incoming request contains the URL and the HTTP method of the request.
- * A {@link RequestKey} for a handler method contains all conditions found in the method @{@link RequestMapping}
- * annotation combined with all conditions found in the type @{@link RequestMapping} annotation, if present.
- *
- *
An incoming request matches to a handler method directly when a @{@link RequestMapping} annotation contains
- * a single, non-pattern URL and a single HTTP method. When a {@link RequestKey} contains additional conditions
- * (e.g. more URL patterns, request parameters, headers, etc) those conditions must be checked against the
- * request rather than against the key that represents it. This results in the creation of a new handler method
- * {@link RequestKey} with the subset of conditions relevant to the current request (see
- * {@link RequestKey#getMatchingKey(HttpServletRequest, PathMatcher, UrlPathHelper)}).
- * Such keys can then be compared against each other, in the context of the current request, making it possible
- * to select to the best matching {@link RequestKey} in case of multiple matches and also the best matching
- * pattern within the selected key.
+ * An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingKey}s for the registration and
+ * the lookup of {@link HandlerMethod}s.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1.0
*/
-public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMapping {
-
- private UrlPathHelper urlPathHelper = new UrlPathHelper();
+public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMapping {
private PathMatcher pathMatcher = new AntPathMatcher();
private MappedInterceptors mappedInterceptors;
- /**
- * Set if URL lookup should always use the full path within the current servlet context. Else, the path within the
- * current servlet mapping is used if applicable (that is, in the case of a ".../*" servlet mapping in web.xml).
- * Default is "false".
- *
- * @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath
- */
- public void setAlwaysUseFullPath(boolean alwaysUseFullPath) {
- this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath);
- }
-
- /**
- * Set if context path and request URI should be URL-decoded. Both are returned undecoded by the Servlet API, in
- * contrast to the servlet path.
Uses either the request encoding or the default encoding according to the Servlet
- * spec (ISO-8859-1).
- *
- * @see org.springframework.web.util.UrlPathHelper#setUrlDecode
- */
- public void setUrlDecode(boolean urlDecode) {
- this.urlPathHelper.setUrlDecode(urlDecode);
- }
-
- /**
- * Set the UrlPathHelper to use for resolution of lookup paths.
Use this to override the default UrlPathHelper
- * with a custom subclass, or to share common UrlPathHelper settings across multiple HandlerMappings and
- * MethodNameResolvers.
- *
- */
- public void setUrlPathHelper(UrlPathHelper urlPathHelper) {
- Assert.notNull(urlPathHelper, "UrlPathHelper must not be null");
- this.urlPathHelper = urlPathHelper;
- }
-
/**
* Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. Default is
* AntPathMatcher.
@@ -145,18 +97,7 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
}
/**
- * Returns a {@link RequestKey} instances that represents the given HTTP servlet request.
- *
- * @param request the request to look up the key for
- * @return the key, never null
- */
- @Override
- protected RequestKey getKeyForRequest(HttpServletRequest request) {
- return RequestKey.createFromServletRequest(request, urlPathHelper);
- }
-
- /**
- * Provides a {@link RequestKey} for the given method.
+ * Provides a {@link RequestMappingKey} for the given method.
*
Only {@link RequestMapping @RequestMapping}-annotated methods are considered.
* Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
* attributes combined with method-level {@link RequestMapping @RequestMapping} attributes.
@@ -164,16 +105,16 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
* @param beanName the name of the bean the method belongs to
* @param method the method to create a key for
* @return the key, or {@code null}
- * @see RequestKey#combine(RequestKey, PathMatcher)
+ * @see RequestMappingKey#combine(RequestMappingKey, PathMatcher)
*/
@Override
- protected RequestKey getKeyForMethod(String beanName, Method method) {
+ protected RequestMappingKey getMappingKeyForMethod(String beanName, Method method) {
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
if (annotation != null) {
- RequestKey methodKey = RequestKey.createFromRequestMapping(annotation);
+ RequestMappingKey methodKey = createFromRequestMapping(annotation);
RequestMapping typeAnnot = getApplicationContext().findAnnotationOnBean(beanName, RequestMapping.class);
if (typeAnnot != null) {
- RequestKey typeKey = RequestKey.createFromRequestMapping(typeAnnot);
+ RequestMappingKey typeKey = createFromRequestMapping(typeAnnot);
return typeKey.combine(methodKey, pathMatcher);
}
else {
@@ -185,41 +126,52 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
}
}
- /**
- * Returns a new {@link RequestKey} with attributes matching to the current request or {@code null}.
- * @see RequestKey#getMatchingKey(HttpServletRequest, PathMatcher, UrlPathHelper)
- */
+ private static RequestMappingKey createFromRequestMapping(RequestMapping annotation) {
+ return new RequestMappingKey(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()),
+ RequestConditionFactory.parseParams(annotation.params()),
+ RequestConditionFactory.parseHeaders(annotation.headers()),
+ RequestConditionFactory.parseConsumes(annotation.consumes())
+ );
+ }
+
@Override
- protected RequestKey getMatchingKey(RequestKey key, HttpServletRequest request) {
- return key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ protected Set getMappingPaths(RequestMappingKey key) {
+ return key.getPatterns();
}
/**
- * Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestKey}.
+ * Returns a new {@link RequestMappingKey} with attributes matching to the current request or {@code null}.
+ * @see RequestMappingKey#getMatchingKey(String, HttpServletRequest, PathMatcher)
*/
@Override
- protected Comparator getKeyComparator(HttpServletRequest request) {
- return new RequestKeyComparator(request);
+ protected RequestMappingKey getMatchingMappingKey(RequestMappingKey key, String lookupPath, HttpServletRequest request) {
+ return key.getMatchingKey(lookupPath, request, pathMatcher);
+ }
+
+ /**
+ * Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestMappingKey}.
+ */
+ @Override
+ protected Comparator getMappingKeyComparator(String lookupPath, HttpServletRequest request) {
+ return new RequestKeyComparator(lookupPath, request);
}
@Override
- protected void handleMatch(RequestKey key, HttpServletRequest request) {
+ protected void handleMatch(RequestMappingKey key, String lookupPath, HttpServletRequest request) {
String pattern = key.getPatterns().iterator().next();
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
Map uriTemplateVariables = pathMatcher.extractUriTemplateVariables(pattern, lookupPath);
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
}
/**
- * Iterates all {@link RequestKey}s looking for keys that match by URL but not by HTTP method.
+ * Iterates all {@link RequestMappingKey}s looking for keys that match by URL but not by HTTP method.
* @exception HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
*/
@Override
- protected HandlerMethod handleNoMatch(Set requestKeys, HttpServletRequest request)
+ protected HandlerMethod handleNoMatch(Set requestKeys, String lookupPath, HttpServletRequest request)
throws HttpRequestMethodNotSupportedException {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
Set allowedMethods = new HashSet(6);
- for (RequestKey requestKey : requestKeys) {
+ for (RequestMappingKey requestKey : requestKeys) {
for (String pattern : requestKey.getPatterns()) {
if (pathMatcher.match(pattern, lookupPath)) {
for (RequestMethod method : requestKey.getMethods()) {
@@ -244,7 +196,7 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
if (this.mappedInterceptors != null) {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
+ String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
HandlerInterceptor[] handlerInterceptors = mappedInterceptors.getInterceptors(lookupPath, pathMatcher);
if (handlerInterceptors.length > 0) {
chain.addInterceptors(handlerInterceptors);
@@ -254,31 +206,30 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
}
/**
- * A comparator for {@link RequestKey}s. Effective comparison can only be done in the context of a
- * specific request. For example not all {@link RequestKey} patterns may apply to the current request.
+ * A comparator for {@link RequestMappingKey}s. Effective comparison can only be done in the context of a
+ * specific request. For example not all {@link RequestMappingKey} patterns may apply to the current request.
* Therefore an HttpServletRequest is required as input.
*
* Furthermore, the following assumptions are made about the input RequestKeys:
*
- Each RequestKey has been fully matched to the request
- The RequestKey contains matched
* patterns only
- Patterns are ordered with the best matching pattern at the top
*
- * @see RequestMappingHandlerMethodMapping#getMatchingKey(RequestKey, HttpServletRequest)
+ * @see RequestMappingHandlerMethodMapping#getMatchingKey(RequestMappingKey, HttpServletRequest)
*/
- private class RequestKeyComparator implements Comparator {
+ private class RequestKeyComparator implements Comparator {
private Comparator patternComparator;
private List requestAcceptHeader;
- public RequestKeyComparator(HttpServletRequest request) {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
+ public RequestKeyComparator(String lookupPath, HttpServletRequest request) {
this.patternComparator = pathMatcher.getPatternComparator(lookupPath);
String acceptHeader = request.getHeader("Accept");
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
MediaType.sortByQualityValue(this.requestAcceptHeader);
}
- public int compare(RequestKey key, RequestKey otherKey) {
+ public int compare(RequestMappingKey key, RequestMappingKey otherKey) {
int result = comparePatterns(key.getPatterns(), otherKey.getPatterns());
if (result != 0) {
return result;
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestKey.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingKey.java
similarity index 75%
rename from org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestKey.java
rename to org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingKey.java
index 16158fe8d21..e46bab74700 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestKey.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingKey.java
@@ -17,37 +17,35 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
+
import javax.servlet.http.HttpServletRequest;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.condition.RequestCondition;
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
-import org.springframework.web.util.UrlPathHelper;
/**
* Contains a set of conditions to match to a given request such as URL patterns, HTTP methods, request
* parameters and headers.
*
- * A {@link RequestKey} can be combined with another {@link RequestKey} resulting in a new {@link RequestKey}
- * with conditions from both (see {@link #combine(RequestKey, PathMatcher)}).
+ *
A {@link RequestMappingKey} can be combined with another {@link RequestMappingKey} resulting in a new {@link RequestMappingKey}
+ * with conditions from both (see {@link #combine(RequestMappingKey, PathMatcher)}).
*
- *
A {@link RequestKey} can be matched to a request resulting in a new {@link RequestKey} with the subset of
- * conditions relevant to the request (see {@link #getMatchingKey(HttpServletRequest, PathMatcher, UrlPathHelper)}).
+ *
A {@link RequestMappingKey} can be matched to a request resulting in a new {@link RequestMappingKey} with the subset of
+ * conditions relevant to the request (see {@link #getMatchingKey(String, HttpServletRequest, PathMatcher)}).
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
*/
-public final class RequestKey {
+public final class RequestMappingKey {
private final Set patterns;
@@ -66,20 +64,18 @@ public final class RequestKey {
*
* Package protected for testing purposes.
*/
- RequestKey(Collection patterns, Collection methods) {
+ RequestMappingKey(Collection patterns, Collection methods) {
this(patterns, methods, null, null, null);
}
/**
* Creates a new {@code RequestKey} instance with a full set of conditions.
- *
- * Package protected for testing purposes.
*/
- RequestKey(Collection patterns,
- Collection methods,
- RequestCondition paramsCondition,
- RequestCondition headersCondition,
- RequestCondition consumesCondition) {
+ public RequestMappingKey(Collection patterns,
+ Collection methods,
+ RequestCondition paramsCondition,
+ RequestCondition headersCondition,
+ RequestCondition consumesCondition) {
this.patterns = asUnmodifiableSet(prependLeadingSlash(patterns));
this.methods = asUnmodifiableSet(methods);
this.paramsCondition = paramsCondition != null ? paramsCondition : RequestConditionFactory.trueCondition();
@@ -109,34 +105,6 @@ public final class RequestKey {
return Collections.unmodifiableSet(result);
}
- /**
- * Creates a new {@code RequestKey} from a {@link RequestMapping @RequestMapping} annotation.
- *
- * @param annotation the annotation
- * @return the request key created from the annotation
- */
- public static RequestKey createFromRequestMapping(RequestMapping annotation) {
- return new RequestKey(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()),
- RequestConditionFactory.parseParams(annotation.params()),
- RequestConditionFactory.parseHeaders(annotation.headers()),
- RequestConditionFactory.parseConsumes(annotation.consumes())
- );
- }
-
- /**
- * Creates a new {@code RequestKey} from a {@link HttpServletRequest}.
- *
- * @param request the servlet request
- * @param urlPathHelper to create the {@linkplain UrlPathHelper#getLookupPathForRequest(HttpServletRequest) lookup
- * path}
- * @return the request key created from the servlet request
- */
- public static RequestKey createFromServletRequest(HttpServletRequest request, UrlPathHelper urlPathHelper) {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
- RequestMethod method = RequestMethod.valueOf(request.getMethod());
- return new RequestKey(Collections.singleton(lookupPath), Collections.singleton(method));
- }
-
/**
* Returns the patterns of this request key.
*/
@@ -183,14 +151,14 @@ public final class RequestKey {
* @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns
* @return a new request key containing conditions from both keys
*/
- public RequestKey combine(RequestKey methodKey, PathMatcher pathMatcher) {
+ public RequestMappingKey combine(RequestMappingKey methodKey, PathMatcher pathMatcher) {
Set patterns = combinePatterns(this.patterns, methodKey.patterns, pathMatcher);
Set methods = union(this.methods, methodKey.methods);
RequestCondition params = RequestConditionFactory.and(this.paramsCondition, methodKey.paramsCondition);
RequestCondition headers = RequestConditionFactory.and(this.headersCondition, methodKey.headersCondition);
RequestCondition consumes = RequestConditionFactory.mostSpecific(methodKey.consumesCondition, this.consumesCondition);
- return new RequestKey(patterns, methods, params, headers, consumes);
+ return new RequestMappingKey(patterns, methods, params, headers, consumes);
}
private static Set combinePatterns(Collection typePatterns,
@@ -231,21 +199,21 @@ public final class RequestKey {
* Request parameter and request header conditions are included in full.
* The list of consumes conditions is trimmed and sorted to match the request "Content-Type" header.
*
+ * @param lookupPath mapping lookup path within the current servlet mapping if applicable
* @param request the current request
* @param pathMatcher to check for matching patterns
- * @param urlPathHelper to derive the lookup path for the request
* @return a new request key that contains all matching attributes, or {@code null} if not all conditions match
*/
- public RequestKey getMatchingKey(HttpServletRequest request, PathMatcher pathMatcher, UrlPathHelper urlPathHelper) {
+ public RequestMappingKey getMatchingKey(String lookupPath, HttpServletRequest request, PathMatcher pathMatcher) {
if (!checkMethod(request) || !paramsCondition.match(request) || !headersCondition.match(request) ||
!consumesCondition.match(request)) {
return null;
}
else {
- List matchingPatterns = getMatchingPatterns(request, pathMatcher, urlPathHelper);
+ List matchingPatterns = getMatchingPatterns(lookupPath, request, pathMatcher);
if (!matchingPatterns.isEmpty()) {
Set matchingMethods = getMatchingMethod(request);
- return new RequestKey(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition,
+ return new RequestMappingKey(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition,
this.consumesCondition);
}
else {
@@ -254,10 +222,9 @@ public final class RequestKey {
}
}
- private List getMatchingPatterns(HttpServletRequest request,
- PathMatcher pathMatcher,
- UrlPathHelper urlPathHelper) {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
+ private List getMatchingPatterns(String lookupPath,
+ HttpServletRequest request,
+ PathMatcher pathMatcher) {
List matchingPatterns = new ArrayList();
for (String pattern : this.patterns) {
@@ -308,8 +275,8 @@ public final class RequestKey {
if (this == obj) {
return true;
}
- if (obj != null && obj instanceof RequestKey) {
- RequestKey other = (RequestKey) obj;
+ if (obj != null && obj instanceof RequestMappingKey) {
+ RequestMappingKey other = (RequestMappingKey) obj;
return (this.patterns.equals(other.patterns) && this.methods.equals(other.methods) &&
this.paramsCondition.equals(other.paramsCondition) &&
this.headersCondition.equals(other.headersCondition));
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/RequestCondition.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/RequestCondition.java
index 7a016b822c8..26fa8880980 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/RequestCondition.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/condition/RequestCondition.java
@@ -20,7 +20,7 @@ import javax.servlet.http.HttpServletRequest;
/**
* Defines the contract for conditions that must be met before an incoming request matches a {@link
- * org.springframework.web.servlet.mvc.method.annotation.RequestKey RequestKey}.
+ * org.springframework.web.servlet.mvc.method.annotation.RequestMappingKey RequestKey}.
*
* Implementations of this interface are created by the {@link RequestConditionFactory}.
*
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java
index e8128ae9d56..c4de71a4842 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java
@@ -16,20 +16,21 @@
package org.springframework.web.servlet.handler;
+import static org.junit.Assert.assertEquals;
+
import java.lang.reflect.Method;
import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
import org.junit.Test;
-
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.util.UrlPathHelper;
-
-import static org.junit.Assert.*;
/**
* Test for {@link AbstractHandlerMethodMapping}.
@@ -54,14 +55,14 @@ public class HandlerMethodMappingTests {
@Test(expected = IllegalStateException.class)
public void registerDuplicates() {
- mapping.registerHandlerMethod("foo", handlerMethod1);
- mapping.registerHandlerMethod("foo", handlerMethod2);
+ mapping.registerHandlerMethod(new HashSet(), "foo", handlerMethod1);
+ mapping.registerHandlerMethod(new HashSet(), "foo", handlerMethod2);
}
@Test
public void directMatch() throws Exception {
String key = "foo";
- mapping.registerHandlerMethod(key, handlerMethod1);
+ mapping.registerHandlerMethod(new HashSet(), key, handlerMethod1);
HandlerMethod result = mapping.getHandlerInternal(new MockHttpServletRequest("GET", key));
assertEquals(handlerMethod1, result);
@@ -69,8 +70,8 @@ public class HandlerMethodMappingTests {
@Test
public void patternMatch() throws Exception {
- mapping.registerHandlerMethod("/fo*", handlerMethod1);
- mapping.registerHandlerMethod("/f*", handlerMethod1);
+ mapping.registerHandlerMethod(new HashSet(), "/fo*", handlerMethod1);
+ mapping.registerHandlerMethod(new HashSet(), "/f*", handlerMethod1);
HandlerMethod result = mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo"));
assertEquals(handlerMethod1, result);
@@ -78,40 +79,29 @@ public class HandlerMethodMappingTests {
@Test(expected = IllegalStateException.class)
public void ambiguousMatch() throws Exception {
- mapping.registerHandlerMethod("/f?o", handlerMethod1);
- mapping.registerHandlerMethod("/fo?", handlerMethod2);
+ mapping.registerHandlerMethod(new HashSet(), "/f?o", handlerMethod1);
+ mapping.registerHandlerMethod(new HashSet(), "/fo?", handlerMethod2);
mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo"));
}
private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping {
- private UrlPathHelper urlPathHelper = new UrlPathHelper();
-
private PathMatcher pathMatcher = new AntPathMatcher();
@Override
- protected String getKeyForRequest(HttpServletRequest request) throws Exception {
- return urlPathHelper.getLookupPathForRequest(request);
- }
-
- @Override
- protected String getMatchingKey(String pattern, HttpServletRequest request) {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
-
+ protected String getMatchingMappingKey(String pattern, String lookupPath, HttpServletRequest request) {
return pathMatcher.match(pattern, lookupPath) ? pattern : null;
}
@Override
- protected String getKeyForMethod(String beanName, Method method) {
+ protected String getMappingKeyForMethod(String beanName, Method method) {
String methodName = method.getName();
return methodName.startsWith("handler") ? methodName : null;
}
@Override
- protected Comparator getKeyComparator(HttpServletRequest request) {
- String lookupPath = urlPathHelper.getLookupPathForRequest(request);
-
+ protected Comparator getMappingKeyComparator(String lookupPath, HttpServletRequest request) {
return pathMatcher.getPatternComparator(lookupPath);
}
@@ -119,6 +109,11 @@ public class HandlerMethodMappingTests {
protected boolean isHandler(String beanName) {
return true;
}
+
+ @Override
+ protected Set getMappingPaths(String key) {
+ return new HashSet();
+ }
}
private static class MyHandler {
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyComparatorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyComparatorTests.java
index 6c91865eaec..555a820cba5 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyComparatorTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyComparatorTests.java
@@ -27,12 +27,13 @@ import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
+import org.springframework.web.util.UrlPathHelper;
import static java.util.Arrays.*;
import static org.junit.Assert.*;
/**
- * Test fixture with {@link RequestMappingHandlerMethodMapping} testing its {@link RequestKey} comparator.
+ * Test fixture with {@link RequestMappingHandlerMethodMapping} testing its {@link RequestMappingKey} comparator.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
@@ -52,9 +53,10 @@ public class RequestKeyComparatorTests {
@Test
public void moreSpecificPatternWins() {
request.setRequestURI("/foo");
- Comparator comparator = handlerMapping.getKeyComparator(request);
- RequestKey key1 = new RequestKey(asList("/fo*"), null);
- RequestKey key2 = new RequestKey(asList("/foo"), null);
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
+ Comparator comparator = handlerMapping.getMappingKeyComparator(lookupPath, request);
+ RequestMappingKey key1 = new RequestMappingKey(asList("/fo*"), null);
+ RequestMappingKey key2 = new RequestMappingKey(asList("/foo"), null);
assertEquals(1, comparator.compare(key1, key2));
}
@@ -62,9 +64,10 @@ public class RequestKeyComparatorTests {
@Test
public void equalPatterns() {
request.setRequestURI("/foo");
- Comparator comparator = handlerMapping.getKeyComparator(request);
- RequestKey key1 = new RequestKey(asList("/foo*"), null);
- RequestKey key2 = new RequestKey(asList("/foo*"), null);
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
+ Comparator comparator = handlerMapping.getMappingKeyComparator(lookupPath, request);
+ RequestMappingKey key1 = new RequestMappingKey(asList("/foo*"), null);
+ RequestMappingKey key2 = new RequestMappingKey(asList("/foo*"), null);
assertEquals(0, comparator.compare(key1, key2));
}
@@ -72,34 +75,35 @@ public class RequestKeyComparatorTests {
@Test
public void greaterNumberOfMatchingPatternsWins() throws Exception {
request.setRequestURI("/foo.html");
- RequestKey key1 = new RequestKey(asList("/foo", "*.jpeg"), null);
- RequestKey key2 = new RequestKey(asList("/foo", "*.html"), null);
- RequestKey match1 = handlerMapping.getMatchingKey(key1, request);
- RequestKey match2 = handlerMapping.getMatchingKey(key2, request);
- List matches = asList(match1, match2);
- Collections.sort(matches, handlerMapping.getKeyComparator(request));
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
+ RequestMappingKey key1 = new RequestMappingKey(asList("/foo", "*.jpeg"), null);
+ RequestMappingKey key2 = new RequestMappingKey(asList("/foo", "*.html"), null);
+ RequestMappingKey match1 = handlerMapping.getMatchingMappingKey(key1, lookupPath, request);
+ RequestMappingKey match2 = handlerMapping.getMatchingMappingKey(key2, lookupPath, request);
+ List matches = asList(match1, match2);
+ Collections.sort(matches, handlerMapping.getMappingKeyComparator(lookupPath, request));
assertSame(match2.getPatterns(), matches.get(0).getPatterns());
}
@Test
public void oneMethodWinsOverNone() {
- Comparator comparator = handlerMapping.getKeyComparator(request);
- RequestKey key1 = new RequestKey(null, null);
- RequestKey key2 = new RequestKey(null, asList(RequestMethod.GET));
+ Comparator comparator = handlerMapping.getMappingKeyComparator("", request);
+ RequestMappingKey key1 = new RequestMappingKey(null, null);
+ RequestMappingKey key2 = new RequestMappingKey(null, asList(RequestMethod.GET));
assertEquals(1, comparator.compare(key1, key2));
}
@Test
public void methodsAndParams() {
- RequestKey empty = new RequestKey(null, null);
- RequestKey oneMethod = new RequestKey(null, asList(RequestMethod.GET));
- RequestKey oneMethodOneParam =
- new RequestKey(null, asList(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null);
- List list = asList(empty, oneMethod, oneMethodOneParam);
+ RequestMappingKey empty = new RequestMappingKey(null, null);
+ RequestMappingKey oneMethod = new RequestMappingKey(null, asList(RequestMethod.GET));
+ RequestMappingKey oneMethodOneParam =
+ new RequestMappingKey(null, asList(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null);
+ List list = asList(empty, oneMethod, oneMethodOneParam);
Collections.shuffle(list);
- Collections.sort(list, handlerMapping.getKeyComparator(request));
+ Collections.sort(list, handlerMapping.getMappingKeyComparator("", request));
assertEquals(oneMethodOneParam, list.get(0));
assertEquals(oneMethod, list.get(1));
@@ -109,12 +113,12 @@ public class RequestKeyComparatorTests {
@Test
@Ignore // TODO : remove ignore
public void acceptHeaders() {
- RequestKey html = new RequestKey(null, null, null, RequestConditionFactory.parseHeaders("accept=text/html"), null);
- RequestKey xml = new RequestKey(null, null, null, RequestConditionFactory.parseHeaders("accept=application/xml"), null);
- RequestKey none = new RequestKey(null, null);
+ RequestMappingKey html = new RequestMappingKey(null, null, null, RequestConditionFactory.parseHeaders("accept=text/html"), null);
+ RequestMappingKey xml = new RequestMappingKey(null, null, null, RequestConditionFactory.parseHeaders("accept=application/xml"), null);
+ RequestMappingKey none = new RequestMappingKey(null, null);
request.addHeader("Accept", "application/xml, text/html");
- Comparator comparator = handlerMapping.getKeyComparator(request);
+ Comparator comparator = handlerMapping.getMappingKeyComparator("", request);
assertTrue(comparator.compare(html, xml) > 0);
assertTrue(comparator.compare(xml, html) < 0);
@@ -125,14 +129,14 @@ public class RequestKeyComparatorTests {
request = new MockHttpServletRequest();
request.addHeader("Accept", "application/xml, text/*");
- comparator = handlerMapping.getKeyComparator(request);
+ comparator = handlerMapping.getMappingKeyComparator("", request);
assertTrue(comparator.compare(html, xml) > 0);
assertTrue(comparator.compare(xml, html) < 0);
request = new MockHttpServletRequest();
request.addHeader("Accept", "application/pdf");
- comparator = handlerMapping.getKeyComparator(request);
+ comparator = handlerMapping.getMappingKeyComparator("", request);
assertTrue(comparator.compare(html, xml) == 0);
assertTrue(comparator.compare(xml, html) == 0);
@@ -140,7 +144,7 @@ public class RequestKeyComparatorTests {
// See SPR-7000
request = new MockHttpServletRequest();
request.addHeader("Accept", "text/html;q=0.9,application/xml");
- comparator = handlerMapping.getKeyComparator(request);
+ comparator = handlerMapping.getMappingKeyComparator("", request);
assertTrue(comparator.compare(html, xml) > 0);
assertTrue(comparator.compare(xml, html) < 0);
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyTests.java
index fbe16149d22..73f941fdff3 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestKeyTests.java
@@ -16,22 +16,23 @@
package org.springframework.web.servlet.mvc.method.annotation;
-import org.junit.Test;
+import static java.util.Arrays.asList;
+import static java.util.Collections.singleton;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.springframework.web.bind.annotation.RequestMethod.GET;
+import static org.springframework.web.bind.annotation.RequestMethod.POST;
+import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
-import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
import org.springframework.web.util.UrlPathHelper;
-import static java.util.Arrays.*;
-import static java.util.Collections.*;
-import static org.junit.Assert.*;
-import static org.springframework.web.bind.annotation.RequestMethod.*;
-
/**
- * Test fixture for {@link RequestKey} tests.
+ * Test fixture for {@link RequestMappingKey} tests.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
@@ -40,8 +41,8 @@ public class RequestKeyTests {
@Test
public void equals() {
- RequestKey key1 = new RequestKey(singleton("/foo"), singleton(GET));
- RequestKey key2 = new RequestKey(singleton("/foo"), singleton(GET));
+ RequestMappingKey key1 = new RequestMappingKey(singleton("/foo"), singleton(GET));
+ RequestMappingKey key2 = new RequestMappingKey(singleton("/foo"), singleton(GET));
assertEquals(key1, key2);
assertEquals(key1.hashCode(), key2.hashCode());
@@ -49,8 +50,8 @@ public class RequestKeyTests {
@Test
public void equalsPrependSlash() {
- RequestKey key1 = new RequestKey(singleton("/foo"), singleton(GET));
- RequestKey key2 = new RequestKey(singleton("foo"), singleton(GET));
+ RequestMappingKey key1 = new RequestMappingKey(singleton("/foo"), singleton(GET));
+ RequestMappingKey key2 = new RequestMappingKey(singleton("foo"), singleton(GET));
assertEquals(key1, key2);
assertEquals(key1.hashCode(), key2.hashCode());
@@ -60,9 +61,9 @@ public class RequestKeyTests {
public void combinePatterns() {
AntPathMatcher pathMatcher = new AntPathMatcher();
- RequestKey key1 = createKeyFromPatterns("/t1", "/t2");
- RequestKey key2 = createKeyFromPatterns("/m1", "/m2");
- RequestKey key3 = createKeyFromPatterns("/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2");
+ RequestMappingKey key1 = createKeyFromPatterns("/t1", "/t2");
+ RequestMappingKey key2 = createKeyFromPatterns("/m1", "/m2");
+ RequestMappingKey key3 = createKeyFromPatterns("/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2");
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
key1 = createKeyFromPatterns("/t1");
@@ -88,154 +89,147 @@ public class RequestKeyTests {
@Test
public void matchPatternsToRequest() {
- UrlPathHelper urlPathHelper = new UrlPathHelper();
+ UrlPathHelper pathHelper = new UrlPathHelper();
PathMatcher pathMatcher = new AntPathMatcher();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
- RequestKey key = new RequestKey(singleton("/foo"), null);
- RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null);
+ RequestMappingKey match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
assertNotNull(match);
request = new MockHttpServletRequest("GET", "/foo/bar");
- key = new RequestKey(singleton("/foo/*"), null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo/*"), null);
+ match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
assertNotNull("Pattern match", match);
request = new MockHttpServletRequest("GET", "/foo.html");
- key = new RequestKey(singleton("/foo"), null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo"), null);
+ match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
assertNotNull("Implicit match by extension", match);
assertEquals("Contains matched pattern", "/foo.*", match.getPatterns().iterator().next());
request = new MockHttpServletRequest("GET", "/foo/");
- key = new RequestKey(singleton("/foo"), null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo"), null);
+ match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
assertNotNull("Implicit match by trailing slash", match);
assertEquals("Contains matched pattern", "/foo/", match.getPatterns().iterator().next());
request = new MockHttpServletRequest("GET", "/foo.html");
- key = new RequestKey(singleton("/foo.jpg"), null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo.jpg"), null);
+ match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
assertNull("Implicit match ignored if pattern has extension", match);
request = new MockHttpServletRequest("GET", "/foo.html");
- key = new RequestKey(singleton("/foo.jpg"), null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo.jpg"), null);
+ match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
assertNull("Implicit match ignored on pattern with trailing slash", match);
}
@Test
public void matchRequestMethods() {
- UrlPathHelper urlPathHelper = new UrlPathHelper();
PathMatcher pathMatcher = new AntPathMatcher();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
- RequestKey key = new RequestKey(singleton("/foo"), null);
- RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null);
+ RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNotNull("No method matches any method", match);
- key = new RequestKey(singleton("/foo"), singleton(GET));
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo"), singleton(GET));
+ match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNotNull("Exact match", match);
- key = new RequestKey(singleton("/foo"), singleton(POST));
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo"), singleton(POST));
+ match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNull("No match", match);
}
@Test
public void matchingKeyContent() {
- UrlPathHelper urlPathHelper = new UrlPathHelper();
PathMatcher pathMatcher = new AntPathMatcher();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
- RequestKey key = new RequestKey(asList("/foo*", "/bar"), asList(GET, POST));
- RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
- RequestKey expected = new RequestKey(singleton("/foo*"), singleton(GET));
+ RequestMappingKey key = new RequestMappingKey(asList("/foo*", "/bar"), asList(GET, POST));
+ RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
+ RequestMappingKey expected = new RequestMappingKey(singleton("/foo*"), singleton(GET));
assertEquals("Matching RequestKey contains matched patterns and methods only", expected, match);
- key = new RequestKey(asList("/**", "/foo*", "/foo"), null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
- expected = new RequestKey(asList("/foo", "/foo*", "/**"), null);
+ key = new RequestMappingKey(asList("/**", "/foo*", "/foo"), null);
+ match = key.getMatchingKey(lookupPath, request, pathMatcher);
+ expected = new RequestMappingKey(asList("/foo", "/foo*", "/**"), null);
assertEquals("Matched patterns are sorted with best match at the top", expected, match);
}
@Test
public void paramsCondition() {
- UrlPathHelper urlPathHelper = new UrlPathHelper();
PathMatcher pathMatcher = new AntPathMatcher();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
request.setParameter("foo", "bar");
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
- RequestKey key = new RequestKey(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null, null);
- RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ RequestMappingKey key = new RequestMappingKey(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null, null);
+ RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNotNull(match);
- key = new RequestKey(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null, null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null, null);
+ match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNull(match);
}
@Test
public void headersCondition() {
- UrlPathHelper urlPathHelper = new UrlPathHelper();
PathMatcher pathMatcher = new AntPathMatcher();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
request.addHeader("foo", "bar");
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
- RequestKey key = new RequestKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"), null);
- RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"), null);
+ RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNotNull(match);
- key = new RequestKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"), null);
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ key = new RequestMappingKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"), null);
+ match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNull(match);
}
@Test
public void consumesCondition() {
- UrlPathHelper urlPathHelper = new UrlPathHelper();
PathMatcher pathMatcher = new AntPathMatcher();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
request.setContentType("text/plain");
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
- RequestKey key = new RequestKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
+ RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
"text/plain"));
- RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNotNull(match);
- key = new RequestKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
+ key = new RequestMappingKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
"application/xml"));
- match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
+ match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNull(match);
}
- @Test
- public void createFromServletRequest() {
- MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
- RequestKey key = RequestKey.createFromServletRequest(request, new UrlPathHelper());
- assertEquals(new RequestKey(singleton("/foo"), singleton(RequestMethod.GET), null, null, null), key);
- }
-
- private RequestKey createKeyFromPatterns(String... patterns) {
- return new RequestKey(asList(patterns), null);
+ private RequestMappingKey createKeyFromPatterns(String... patterns) {
+ return new RequestMappingKey(asList(patterns), null);
}
}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMappingTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMappingTests.java
index dc24f57000b..bb8254b82ee 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMappingTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodMappingTests.java
@@ -27,7 +27,6 @@ import java.util.Arrays;
import java.util.Map;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -41,6 +40,7 @@ import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.servlet.handler.MappedInterceptor;
+import org.springframework.web.util.UrlPathHelper;
/**
* Test fixture with {@link RequestMappingHandlerMethodMapping}.
@@ -102,8 +102,6 @@ public class RequestMappingHandlerMethodMappingTests {
assertEquals(emptyMethod.getMethod(), hm.getMethod());
}
- // TODO: SPR-8247
- @Ignore
@Test
public void bestMatch() throws Exception {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
@@ -126,10 +124,11 @@ public class RequestMappingHandlerMethodMappingTests {
@Test
public void uriTemplateVariables() {
- RequestKey key = new RequestKey(Arrays.asList("/{path1}/{path2}"), null);
+ RequestMappingKey key = new RequestMappingKey(Arrays.asList("/{path1}/{path2}"), null);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/1/2");
+ String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
- mapping.handleMatch(key, request);
+ mapping.handleMatch(key, lookupPath, request);
@SuppressWarnings("unchecked")
Map actual = (Map) request.getAttribute(