SPR-8247
This commit is contained in:
parent
57d327d1ff
commit
d14c7f2d09
|
|
@ -30,27 +30,18 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.context.ApplicationContextException;
|
import org.springframework.context.ApplicationContextException;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.LinkedMultiValueMap;
|
||||||
|
import org.springframework.util.MultiValueMap;
|
||||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.method.HandlerMethodSelector;
|
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
|
* Abstract base class for {@link org.springframework.web.servlet.HandlerMapping HandlerMapping} implementations that
|
||||||
* support mapping requests to {@link HandlerMethod}s rather than to handlers.
|
* support mapping requests to {@link HandlerMethod}s rather than to handlers.
|
||||||
*
|
*
|
||||||
* <p>Each {@link HandlerMethod} is registered with a unique key. Subclasses define the key type and how to create it
|
* @param <T> Represents a mapping key with conditions for mapping a request to a {@link HandlerMethod}.
|
||||||
* for a given handler method. Keys represent conditions for matching a handler method to a request.
|
|
||||||
*
|
|
||||||
* <p>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.
|
|
||||||
*
|
|
||||||
* <p>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 <T> A unique key for the registration of mapped {@link HandlerMethod}s representing the conditions to
|
|
||||||
* match a handler method to a request.
|
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
|
@ -58,8 +49,52 @@ import org.springframework.web.method.HandlerMethodSelector;
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
|
public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping {
|
||||||
|
|
||||||
|
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
||||||
|
|
||||||
|
private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
|
||||||
|
|
||||||
private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
|
private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
* <p>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 <i>undecoded</i> by the Servlet API, in
|
||||||
|
* contrast to the servlet path. <p>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. <p>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.
|
* Calls the initialization of the superclass and detects handlers.
|
||||||
*/
|
*/
|
||||||
|
|
@ -71,14 +106,12 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register handler methods found in beans of the current ApplicationContext.
|
* Register handler methods found in beans of the current ApplicationContext.
|
||||||
* <p>The actual key determination for a handler is up to the concrete
|
* <p>The actual mapping for a handler is up to the concrete {@link #getMappingKeyForMethod(String, Method)}
|
||||||
* {@link #getKeyForMethod(Method)} implementation. A method in a bean for which no key
|
* implementation.
|
||||||
* could be determined is simply not considered a handler method.
|
|
||||||
* @see #getKeyForMethod(Method)
|
|
||||||
*/
|
*/
|
||||||
protected void initHandlerMethods() {
|
protected void initHandlerMethods() {
|
||||||
if (logger.isDebugEnabled()) {
|
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)) {
|
for (String beanName : getApplicationContext().getBeanNamesForType(Object.class)) {
|
||||||
if (isHandler(beanName)){
|
if (isHandler(beanName)){
|
||||||
|
|
@ -102,81 +135,79 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||||
|
|
||||||
Set<Method> methods = HandlerMethodSelector.selectMethods(handlerType, new MethodFilter() {
|
Set<Method> methods = HandlerMethodSelector.selectMethods(handlerType, new MethodFilter() {
|
||||||
public boolean matches(Method method) {
|
public boolean matches(Method method) {
|
||||||
return getKeyForMethod(beanName, method) != null;
|
return getMappingKeyForMethod(beanName, method) != null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
for (Method method : methods) {
|
for (Method method : methods) {
|
||||||
T key = getKeyForMethod(beanName, method);
|
|
||||||
HandlerMethod handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
|
HandlerMethod handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
|
||||||
registerHandlerMethod(key, handlerMethod);
|
T mapping = getMappingKeyForMethod(beanName, method);
|
||||||
|
Set<String> 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.
|
* not considered a handler method.
|
||||||
*
|
*
|
||||||
* @param beanName the name of the bean the method belongs to
|
* @param beanName the name of the bean the method belongs to
|
||||||
* @param method the method to create a key for
|
* @param method the method to create a mapping for
|
||||||
* @return the lookup key, or {@code null} if the method has none
|
* @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.
|
* Registers a {@link HandlerMethod} with the given mapping.
|
||||||
*
|
*
|
||||||
* @param key the key to register the method under
|
* @param paths URL paths mapped to this method
|
||||||
|
* @param mappingKey the mapping key for the method
|
||||||
* @param handlerMethod the handler method to register
|
* @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) {
|
protected void registerHandlerMethod(Set<String> paths, T mappingKey, HandlerMethod handlerMethod) {
|
||||||
Assert.notNull(key, "'key' must not be null");
|
Assert.notNull(mappingKey, "'mapping' must not be null");
|
||||||
Assert.notNull(handlerMethod, "'handlerMethod' 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)) {
|
if (mappedHandlerMethod != null && !mappedHandlerMethod.equals(handlerMethod)) {
|
||||||
throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + handlerMethod.getBean()
|
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.");
|
+ mappedHandlerMethod.getBean() + "' bean method\n" + mappedHandlerMethod + " mapped.");
|
||||||
}
|
}
|
||||||
handlerMethods.put(key, handlerMethod);
|
handlerMethods.put(mappingKey, handlerMethod);
|
||||||
if (logger.isInfoEnabled()) {
|
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<String> getMappingPaths(T mappingKey);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
|
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
|
||||||
T key = getKeyForRequest(request);
|
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
||||||
if (key == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (logger.isDebugEnabled()) {
|
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 (logger.isDebugEnabled()) {
|
||||||
if (handlerMethod != null) {
|
if (handlerMethod != null) {
|
||||||
logger.debug("Returning handler method [" + handlerMethod + "]");
|
logger.debug("Returning handler method [" + handlerMethod + "]");
|
||||||
}
|
}
|
||||||
else {
|
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;
|
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.
|
* Looks up the best-matching {@link HandlerMethod} for the given request.
|
||||||
*
|
*
|
||||||
|
|
@ -185,35 +216,31 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||||
* returns the 1st entry, if any. If no matches are found, {@link #handleNoMatch(Set, HttpServletRequest)} is
|
* returns the 1st entry, if any. If no matches are found, {@link #handleNoMatch(Set, HttpServletRequest)} is
|
||||||
* invoked.
|
* 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
|
* @param request the current HTTP servlet request
|
||||||
* @return the best-matching handler method, or {@code null} if there is no match
|
* @return the best-matching handler method, or {@code null} if there is no match
|
||||||
*/
|
*/
|
||||||
protected HandlerMethod lookupHandlerMethod(T lookupKey, HttpServletRequest request) throws Exception {
|
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
|
||||||
if (handlerMethods.containsKey(lookupKey)) {
|
List<T> keys = urlMap.get(lookupPath);
|
||||||
if (logger.isTraceEnabled()) {
|
if (keys == null) {
|
||||||
logger.trace("Found direct match for [" + lookupKey + "]");
|
keys = new ArrayList<T>(handlerMethods.keySet());
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMatch(lookupKey, request);
|
|
||||||
return handlerMethods.get(lookupKey);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
List<Match> matches = new ArrayList<Match>();
|
List<Match> matches = new ArrayList<Match>();
|
||||||
|
|
||||||
for (Map.Entry<T, HandlerMethod> entry : handlerMethods.entrySet()) {
|
for (T key : keys) {
|
||||||
T match = getMatchingKey(entry.getKey(), request);
|
T match = getMatchingMappingKey(key, lookupPath, request);
|
||||||
if (match != null) {
|
if (match != null) {
|
||||||
matches.add(new Match(match, entry.getValue()));
|
matches.add(new Match(match, handlerMethods.get(key)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matches.isEmpty()) {
|
if (!matches.isEmpty()) {
|
||||||
Comparator<Match> comparator = getMatchComparator(request);
|
Comparator<Match> comparator = new MatchComparator(getMappingKeyComparator(lookupPath, request));
|
||||||
Collections.sort(matches, comparator);
|
Collections.sort(matches, comparator);
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.trace("Found " + matches.size() + " matching key(s) for [" + lookupKey + "] : " + matches);
|
logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
|
||||||
}
|
}
|
||||||
|
|
||||||
Match bestMatch = matches.get(0);
|
Match bestMatch = matches.get(0);
|
||||||
|
|
@ -228,75 +255,86 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleMatch(bestMatch.key, request);
|
handleMatch(bestMatch.mappingKey, lookupPath, request);
|
||||||
return bestMatch.handlerMethod;
|
return bestMatch.handlerMethod;
|
||||||
}
|
}
|
||||||
else {
|
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
|
* @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
|
* @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);
|
protected abstract T getMatchingMappingKey(T mappingKey, String lookupPath, HttpServletRequest request);
|
||||||
|
|
||||||
private Comparator<Match> getMatchComparator(HttpServletRequest request) {
|
|
||||||
final Comparator<T> keyComparator = getKeyComparator(request);
|
|
||||||
return new Comparator<Match>() {
|
|
||||||
public int compare(Match m1, Match m2) {
|
|
||||||
return keyComparator.compare(m1.key, m2.key);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
* @param request the current HTTP servlet request
|
||||||
* @return the comparator
|
* @return the comparator
|
||||||
*/
|
*/
|
||||||
protected abstract Comparator<T> getKeyComparator(HttpServletRequest request);
|
protected abstract Comparator<T> getMappingKeyComparator(String lookupPath, HttpServletRequest request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoked when no match was found. Default implementation returns {@code null}.
|
* 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
|
* @param request the current HTTP request
|
||||||
* @throws ServletException in case of errors
|
* @throws ServletException in case of errors
|
||||||
*/
|
*/
|
||||||
protected HandlerMethod handleNoMatch(Set<T> requestKeys, HttpServletRequest request) throws Exception {
|
protected HandlerMethod handleNoMatch(Set<T> mappingKeys, String lookupPath, HttpServletRequest request)
|
||||||
|
throws Exception {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Match {
|
private class Match {
|
||||||
|
|
||||||
private final T key;
|
private final T mappingKey;
|
||||||
|
|
||||||
private final HandlerMethod handlerMethod;
|
private final HandlerMethod handlerMethod;
|
||||||
|
|
||||||
private Match(T key, HandlerMethod handlerMethod) {
|
private Match(T mapping, HandlerMethod handlerMethod) {
|
||||||
this.key = key;
|
this.mappingKey = mapping;
|
||||||
this.handlerMethod = handlerMethod;
|
this.handlerMethod = handlerMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return key.toString();
|
return mappingKey.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class MatchComparator implements Comparator<Match> {
|
||||||
|
|
||||||
|
private final Comparator<T> comparator;
|
||||||
|
|
||||||
|
public MatchComparator(Comparator<T> comparator) {
|
||||||
|
this.comparator = comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(Match match1, Match match2) {
|
||||||
|
return comparator.compare(match1.mappingKey, match2.mappingKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package org.springframework.web.servlet.mvc.method.annotation;
|
package org.springframework.web.servlet.mvc.method.annotation;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
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.AbstractHandlerMethodMapping;
|
||||||
import org.springframework.web.servlet.handler.MappedInterceptor;
|
import org.springframework.web.servlet.handler.MappedInterceptor;
|
||||||
import org.springframework.web.servlet.handler.MappedInterceptors;
|
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
|
* An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingKey}s for the registration and
|
||||||
* of {@link HandlerMethod}s.
|
* the lookup of {@link HandlerMethod}s.
|
||||||
*
|
|
||||||
* <p>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.
|
|
||||||
*
|
|
||||||
* <p>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.
|
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 3.1.0
|
* @since 3.1.0
|
||||||
*/
|
*/
|
||||||
public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMapping<RequestKey> {
|
public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMapping<RequestMappingKey> {
|
||||||
|
|
||||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
|
|
||||||
private PathMatcher pathMatcher = new AntPathMatcher();
|
private PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
|
|
||||||
private MappedInterceptors mappedInterceptors;
|
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).
|
|
||||||
* <p>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 <i>undecoded</i> by the Servlet API, in
|
|
||||||
* contrast to the servlet path. <p>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. <p>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
|
* Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. Default is
|
||||||
* AntPathMatcher.
|
* AntPathMatcher.
|
||||||
|
|
@ -145,18 +97,7 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link RequestKey} instances that represents the given HTTP servlet request.
|
* Provides a {@link RequestMappingKey} for the given method.
|
||||||
*
|
|
||||||
* @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.
|
|
||||||
* <p>Only {@link RequestMapping @RequestMapping}-annotated methods are considered.
|
* <p>Only {@link RequestMapping @RequestMapping}-annotated methods are considered.
|
||||||
* Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
|
* Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
|
||||||
* attributes combined with method-level {@link RequestMapping @RequestMapping} attributes.
|
* 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 beanName the name of the bean the method belongs to
|
||||||
* @param method the method to create a key for
|
* @param method the method to create a key for
|
||||||
* @return the key, or {@code null}
|
* @return the key, or {@code null}
|
||||||
* @see RequestKey#combine(RequestKey, PathMatcher)
|
* @see RequestMappingKey#combine(RequestMappingKey, PathMatcher)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected RequestKey getKeyForMethod(String beanName, Method method) {
|
protected RequestMappingKey getMappingKeyForMethod(String beanName, Method method) {
|
||||||
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
RequestKey methodKey = RequestKey.createFromRequestMapping(annotation);
|
RequestMappingKey methodKey = createFromRequestMapping(annotation);
|
||||||
RequestMapping typeAnnot = getApplicationContext().findAnnotationOnBean(beanName, RequestMapping.class);
|
RequestMapping typeAnnot = getApplicationContext().findAnnotationOnBean(beanName, RequestMapping.class);
|
||||||
if (typeAnnot != null) {
|
if (typeAnnot != null) {
|
||||||
RequestKey typeKey = RequestKey.createFromRequestMapping(typeAnnot);
|
RequestMappingKey typeKey = createFromRequestMapping(typeAnnot);
|
||||||
return typeKey.combine(methodKey, pathMatcher);
|
return typeKey.combine(methodKey, pathMatcher);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -185,41 +126,52 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static RequestMappingKey createFromRequestMapping(RequestMapping annotation) {
|
||||||
* Returns a new {@link RequestKey} with attributes matching to the current request or {@code null}.
|
return new RequestMappingKey(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()),
|
||||||
* @see RequestKey#getMatchingKey(HttpServletRequest, PathMatcher, UrlPathHelper)
|
RequestConditionFactory.parseParams(annotation.params()),
|
||||||
*/
|
RequestConditionFactory.parseHeaders(annotation.headers()),
|
||||||
@Override
|
RequestConditionFactory.parseConsumes(annotation.consumes())
|
||||||
protected RequestKey getMatchingKey(RequestKey key, HttpServletRequest request) {
|
);
|
||||||
return key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestKey}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Comparator<RequestKey> getKeyComparator(HttpServletRequest request) {
|
|
||||||
return new RequestKeyComparator(request);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void handleMatch(RequestKey key, HttpServletRequest request) {
|
protected Set<String> getMappingPaths(RequestMappingKey key) {
|
||||||
|
return key.getPatterns();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link RequestMappingKey} with attributes matching to the current request or {@code null}.
|
||||||
|
* @see RequestMappingKey#getMatchingKey(String, HttpServletRequest, PathMatcher)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
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<RequestMappingKey> getMappingKeyComparator(String lookupPath, HttpServletRequest request) {
|
||||||
|
return new RequestKeyComparator(lookupPath, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handleMatch(RequestMappingKey key, String lookupPath, HttpServletRequest request) {
|
||||||
String pattern = key.getPatterns().iterator().next();
|
String pattern = key.getPatterns().iterator().next();
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
|
||||||
Map<String, String> uriTemplateVariables = pathMatcher.extractUriTemplateVariables(pattern, lookupPath);
|
Map<String, String> uriTemplateVariables = pathMatcher.extractUriTemplateVariables(pattern, lookupPath);
|
||||||
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
|
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
|
* @exception HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected HandlerMethod handleNoMatch(Set<RequestKey> requestKeys, HttpServletRequest request)
|
protected HandlerMethod handleNoMatch(Set<RequestMappingKey> requestKeys, String lookupPath, HttpServletRequest request)
|
||||||
throws HttpRequestMethodNotSupportedException {
|
throws HttpRequestMethodNotSupportedException {
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
|
||||||
Set<String> allowedMethods = new HashSet<String>(6);
|
Set<String> allowedMethods = new HashSet<String>(6);
|
||||||
for (RequestKey requestKey : requestKeys) {
|
for (RequestMappingKey requestKey : requestKeys) {
|
||||||
for (String pattern : requestKey.getPatterns()) {
|
for (String pattern : requestKey.getPatterns()) {
|
||||||
if (pathMatcher.match(pattern, lookupPath)) {
|
if (pathMatcher.match(pattern, lookupPath)) {
|
||||||
for (RequestMethod method : requestKey.getMethods()) {
|
for (RequestMethod method : requestKey.getMethods()) {
|
||||||
|
|
@ -244,7 +196,7 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
|
||||||
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
|
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
|
||||||
HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
|
HandlerExecutionChain chain = super.getHandlerExecutionChain(handler, request);
|
||||||
if (this.mappedInterceptors != null) {
|
if (this.mappedInterceptors != null) {
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
|
||||||
HandlerInterceptor[] handlerInterceptors = mappedInterceptors.getInterceptors(lookupPath, pathMatcher);
|
HandlerInterceptor[] handlerInterceptors = mappedInterceptors.getInterceptors(lookupPath, pathMatcher);
|
||||||
if (handlerInterceptors.length > 0) {
|
if (handlerInterceptors.length > 0) {
|
||||||
chain.addInterceptors(handlerInterceptors);
|
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
|
* A comparator for {@link RequestMappingKey}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.
|
* specific request. For example not all {@link RequestMappingKey} patterns may apply to the current request.
|
||||||
* Therefore an HttpServletRequest is required as input.
|
* Therefore an HttpServletRequest is required as input.
|
||||||
*
|
*
|
||||||
* <p>Furthermore, the following assumptions are made about the input RequestKeys:
|
* <p>Furthermore, the following assumptions are made about the input RequestKeys:
|
||||||
* <ul><li>Each RequestKey has been fully matched to the request <li>The RequestKey contains matched
|
* <ul><li>Each RequestKey has been fully matched to the request <li>The RequestKey contains matched
|
||||||
* patterns only <li>Patterns are ordered with the best matching pattern at the top </ul>
|
* patterns only <li>Patterns are ordered with the best matching pattern at the top </ul>
|
||||||
*
|
*
|
||||||
* @see RequestMappingHandlerMethodMapping#getMatchingKey(RequestKey, HttpServletRequest)
|
* @see RequestMappingHandlerMethodMapping#getMatchingKey(RequestMappingKey, HttpServletRequest)
|
||||||
*/
|
*/
|
||||||
private class RequestKeyComparator implements Comparator<RequestKey> {
|
private class RequestKeyComparator implements Comparator<RequestMappingKey> {
|
||||||
|
|
||||||
private Comparator<String> patternComparator;
|
private Comparator<String> patternComparator;
|
||||||
|
|
||||||
private List<MediaType> requestAcceptHeader;
|
private List<MediaType> requestAcceptHeader;
|
||||||
|
|
||||||
public RequestKeyComparator(HttpServletRequest request) {
|
public RequestKeyComparator(String lookupPath, HttpServletRequest request) {
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
|
||||||
this.patternComparator = pathMatcher.getPatternComparator(lookupPath);
|
this.patternComparator = pathMatcher.getPatternComparator(lookupPath);
|
||||||
String acceptHeader = request.getHeader("Accept");
|
String acceptHeader = request.getHeader("Accept");
|
||||||
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
|
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
|
||||||
MediaType.sortByQualityValue(this.requestAcceptHeader);
|
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());
|
int result = comparePatterns(key.getPatterns(), otherKey.getPatterns());
|
||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
return result;
|
return result;
|
||||||
|
|
|
||||||
|
|
@ -17,37 +17,35 @@
|
||||||
package org.springframework.web.servlet.mvc.method.annotation;
|
package org.springframework.web.servlet.mvc.method.annotation;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.springframework.util.PathMatcher;
|
import org.springframework.util.PathMatcher;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.servlet.mvc.method.condition.RequestCondition;
|
import org.springframework.web.servlet.mvc.method.condition.RequestCondition;
|
||||||
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
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
|
* Contains a set of conditions to match to a given request such as URL patterns, HTTP methods, request
|
||||||
* parameters and headers.
|
* parameters and headers.
|
||||||
*
|
*
|
||||||
* <p>A {@link RequestKey} can be combined with another {@link RequestKey} resulting in a new {@link RequestKey}
|
* <p>A {@link RequestMappingKey} can be combined with another {@link RequestMappingKey} resulting in a new {@link RequestMappingKey}
|
||||||
* with conditions from both (see {@link #combine(RequestKey, PathMatcher)}).
|
* with conditions from both (see {@link #combine(RequestMappingKey, PathMatcher)}).
|
||||||
*
|
*
|
||||||
* <p>A {@link RequestKey} can be matched to a request resulting in a new {@link RequestKey} with the subset of
|
* <p>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(HttpServletRequest, PathMatcher, UrlPathHelper)}).
|
* conditions relevant to the request (see {@link #getMatchingKey(String, HttpServletRequest, PathMatcher)}).
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 3.1
|
* @since 3.1
|
||||||
*/
|
*/
|
||||||
public final class RequestKey {
|
public final class RequestMappingKey {
|
||||||
|
|
||||||
private final Set<String> patterns;
|
private final Set<String> patterns;
|
||||||
|
|
||||||
|
|
@ -66,16 +64,14 @@ public final class RequestKey {
|
||||||
*
|
*
|
||||||
* <p>Package protected for testing purposes.
|
* <p>Package protected for testing purposes.
|
||||||
*/
|
*/
|
||||||
RequestKey(Collection<String> patterns, Collection<RequestMethod> methods) {
|
RequestMappingKey(Collection<String> patterns, Collection<RequestMethod> methods) {
|
||||||
this(patterns, methods, null, null, null);
|
this(patterns, methods, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@code RequestKey} instance with a full set of conditions.
|
* Creates a new {@code RequestKey} instance with a full set of conditions.
|
||||||
*
|
|
||||||
* <p>Package protected for testing purposes.
|
|
||||||
*/
|
*/
|
||||||
RequestKey(Collection<String> patterns,
|
public RequestMappingKey(Collection<String> patterns,
|
||||||
Collection<RequestMethod> methods,
|
Collection<RequestMethod> methods,
|
||||||
RequestCondition paramsCondition,
|
RequestCondition paramsCondition,
|
||||||
RequestCondition headersCondition,
|
RequestCondition headersCondition,
|
||||||
|
|
@ -109,34 +105,6 @@ public final class RequestKey {
|
||||||
return Collections.unmodifiableSet(result);
|
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.
|
* 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
|
* @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns
|
||||||
* @return a new request key containing conditions from both keys
|
* @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<String> patterns = combinePatterns(this.patterns, methodKey.patterns, pathMatcher);
|
Set<String> patterns = combinePatterns(this.patterns, methodKey.patterns, pathMatcher);
|
||||||
Set<RequestMethod> methods = union(this.methods, methodKey.methods);
|
Set<RequestMethod> methods = union(this.methods, methodKey.methods);
|
||||||
RequestCondition params = RequestConditionFactory.and(this.paramsCondition, methodKey.paramsCondition);
|
RequestCondition params = RequestConditionFactory.and(this.paramsCondition, methodKey.paramsCondition);
|
||||||
RequestCondition headers = RequestConditionFactory.and(this.headersCondition, methodKey.headersCondition);
|
RequestCondition headers = RequestConditionFactory.and(this.headersCondition, methodKey.headersCondition);
|
||||||
RequestCondition consumes = RequestConditionFactory.mostSpecific(methodKey.consumesCondition, this.consumesCondition);
|
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<String> combinePatterns(Collection<String> typePatterns,
|
private static Set<String> combinePatterns(Collection<String> typePatterns,
|
||||||
|
|
@ -231,21 +199,21 @@ public final class RequestKey {
|
||||||
* <li>Request parameter and request header conditions are included in full.
|
* <li>Request parameter and request header conditions are included in full.
|
||||||
* <li>The list of consumes conditions is trimmed and sorted to match the request "Content-Type" header.
|
* <li>The list of consumes conditions is trimmed and sorted to match the request "Content-Type" header.
|
||||||
* </ul>
|
* </ul>
|
||||||
|
* @param lookupPath mapping lookup path within the current servlet mapping if applicable
|
||||||
* @param request the current request
|
* @param request the current request
|
||||||
* @param pathMatcher to check for matching patterns
|
* @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
|
* @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) ||
|
if (!checkMethod(request) || !paramsCondition.match(request) || !headersCondition.match(request) ||
|
||||||
!consumesCondition.match(request)) {
|
!consumesCondition.match(request)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
List<String> matchingPatterns = getMatchingPatterns(request, pathMatcher, urlPathHelper);
|
List<String> matchingPatterns = getMatchingPatterns(lookupPath, request, pathMatcher);
|
||||||
if (!matchingPatterns.isEmpty()) {
|
if (!matchingPatterns.isEmpty()) {
|
||||||
Set<RequestMethod> matchingMethods = getMatchingMethod(request);
|
Set<RequestMethod> matchingMethods = getMatchingMethod(request);
|
||||||
return new RequestKey(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition,
|
return new RequestMappingKey(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition,
|
||||||
this.consumesCondition);
|
this.consumesCondition);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -254,10 +222,9 @@ public final class RequestKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getMatchingPatterns(HttpServletRequest request,
|
private List<String> getMatchingPatterns(String lookupPath,
|
||||||
PathMatcher pathMatcher,
|
HttpServletRequest request,
|
||||||
UrlPathHelper urlPathHelper) {
|
PathMatcher pathMatcher) {
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
|
||||||
|
|
||||||
List<String> matchingPatterns = new ArrayList<String>();
|
List<String> matchingPatterns = new ArrayList<String>();
|
||||||
for (String pattern : this.patterns) {
|
for (String pattern : this.patterns) {
|
||||||
|
|
@ -308,8 +275,8 @@ public final class RequestKey {
|
||||||
if (this == obj) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (obj != null && obj instanceof RequestKey) {
|
if (obj != null && obj instanceof RequestMappingKey) {
|
||||||
RequestKey other = (RequestKey) obj;
|
RequestMappingKey other = (RequestMappingKey) obj;
|
||||||
return (this.patterns.equals(other.patterns) && this.methods.equals(other.methods) &&
|
return (this.patterns.equals(other.patterns) && this.methods.equals(other.methods) &&
|
||||||
this.paramsCondition.equals(other.paramsCondition) &&
|
this.paramsCondition.equals(other.paramsCondition) &&
|
||||||
this.headersCondition.equals(other.headersCondition));
|
this.headersCondition.equals(other.headersCondition));
|
||||||
|
|
@ -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
|
* 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}.
|
||||||
*
|
*
|
||||||
* <p>Implementations of this interface are created by the {@link RequestConditionFactory}.
|
* <p>Implementations of this interface are created by the {@link RequestConditionFactory}.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -16,20 +16,21 @@
|
||||||
|
|
||||||
package org.springframework.web.servlet.handler;
|
package org.springframework.web.servlet.handler;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.PathMatcher;
|
import org.springframework.util.PathMatcher;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.util.UrlPathHelper;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test for {@link AbstractHandlerMethodMapping}.
|
* Test for {@link AbstractHandlerMethodMapping}.
|
||||||
|
|
@ -54,14 +55,14 @@ public class HandlerMethodMappingTests {
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void registerDuplicates() {
|
public void registerDuplicates() {
|
||||||
mapping.registerHandlerMethod("foo", handlerMethod1);
|
mapping.registerHandlerMethod(new HashSet<String>(), "foo", handlerMethod1);
|
||||||
mapping.registerHandlerMethod("foo", handlerMethod2);
|
mapping.registerHandlerMethod(new HashSet<String>(), "foo", handlerMethod2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void directMatch() throws Exception {
|
public void directMatch() throws Exception {
|
||||||
String key = "foo";
|
String key = "foo";
|
||||||
mapping.registerHandlerMethod(key, handlerMethod1);
|
mapping.registerHandlerMethod(new HashSet<String>(), key, handlerMethod1);
|
||||||
|
|
||||||
HandlerMethod result = mapping.getHandlerInternal(new MockHttpServletRequest("GET", key));
|
HandlerMethod result = mapping.getHandlerInternal(new MockHttpServletRequest("GET", key));
|
||||||
assertEquals(handlerMethod1, result);
|
assertEquals(handlerMethod1, result);
|
||||||
|
|
@ -69,8 +70,8 @@ public class HandlerMethodMappingTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void patternMatch() throws Exception {
|
public void patternMatch() throws Exception {
|
||||||
mapping.registerHandlerMethod("/fo*", handlerMethod1);
|
mapping.registerHandlerMethod(new HashSet<String>(), "/fo*", handlerMethod1);
|
||||||
mapping.registerHandlerMethod("/f*", handlerMethod1);
|
mapping.registerHandlerMethod(new HashSet<String>(), "/f*", handlerMethod1);
|
||||||
|
|
||||||
HandlerMethod result = mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo"));
|
HandlerMethod result = mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo"));
|
||||||
assertEquals(handlerMethod1, result);
|
assertEquals(handlerMethod1, result);
|
||||||
|
|
@ -78,40 +79,29 @@ public class HandlerMethodMappingTests {
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
public void ambiguousMatch() throws Exception {
|
public void ambiguousMatch() throws Exception {
|
||||||
mapping.registerHandlerMethod("/f?o", handlerMethod1);
|
mapping.registerHandlerMethod(new HashSet<String>(), "/f?o", handlerMethod1);
|
||||||
mapping.registerHandlerMethod("/fo?", handlerMethod2);
|
mapping.registerHandlerMethod(new HashSet<String>(), "/fo?", handlerMethod2);
|
||||||
|
|
||||||
mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo"));
|
mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping<String> {
|
private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping<String> {
|
||||||
|
|
||||||
private UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
|
|
||||||
private PathMatcher pathMatcher = new AntPathMatcher();
|
private PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getKeyForRequest(HttpServletRequest request) throws Exception {
|
protected String getMatchingMappingKey(String pattern, String lookupPath, HttpServletRequest request) {
|
||||||
return urlPathHelper.getLookupPathForRequest(request);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getMatchingKey(String pattern, HttpServletRequest request) {
|
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
|
||||||
|
|
||||||
return pathMatcher.match(pattern, lookupPath) ? pattern : null;
|
return pathMatcher.match(pattern, lookupPath) ? pattern : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected String getKeyForMethod(String beanName, Method method) {
|
protected String getMappingKeyForMethod(String beanName, Method method) {
|
||||||
String methodName = method.getName();
|
String methodName = method.getName();
|
||||||
return methodName.startsWith("handler") ? methodName : null;
|
return methodName.startsWith("handler") ? methodName : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Comparator<String> getKeyComparator(HttpServletRequest request) {
|
protected Comparator<String> getMappingKeyComparator(String lookupPath, HttpServletRequest request) {
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
|
||||||
|
|
||||||
return pathMatcher.getPatternComparator(lookupPath);
|
return pathMatcher.getPatternComparator(lookupPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,6 +109,11 @@ public class HandlerMethodMappingTests {
|
||||||
protected boolean isHandler(String beanName) {
|
protected boolean isHandler(String beanName) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<String> getMappingPaths(String key) {
|
||||||
|
return new HashSet<String>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MyHandler {
|
private static class MyHandler {
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,13 @@ import org.junit.Test;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
||||||
|
import org.springframework.web.util.UrlPathHelper;
|
||||||
|
|
||||||
import static java.util.Arrays.*;
|
import static java.util.Arrays.*;
|
||||||
import static org.junit.Assert.*;
|
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 Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
|
@ -52,9 +53,10 @@ public class RequestKeyComparatorTests {
|
||||||
@Test
|
@Test
|
||||||
public void moreSpecificPatternWins() {
|
public void moreSpecificPatternWins() {
|
||||||
request.setRequestURI("/foo");
|
request.setRequestURI("/foo");
|
||||||
Comparator<RequestKey> comparator = handlerMapping.getKeyComparator(request);
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
RequestKey key1 = new RequestKey(asList("/fo*"), null);
|
Comparator<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator(lookupPath, request);
|
||||||
RequestKey key2 = new RequestKey(asList("/foo"), null);
|
RequestMappingKey key1 = new RequestMappingKey(asList("/fo*"), null);
|
||||||
|
RequestMappingKey key2 = new RequestMappingKey(asList("/foo"), null);
|
||||||
|
|
||||||
assertEquals(1, comparator.compare(key1, key2));
|
assertEquals(1, comparator.compare(key1, key2));
|
||||||
}
|
}
|
||||||
|
|
@ -62,9 +64,10 @@ public class RequestKeyComparatorTests {
|
||||||
@Test
|
@Test
|
||||||
public void equalPatterns() {
|
public void equalPatterns() {
|
||||||
request.setRequestURI("/foo");
|
request.setRequestURI("/foo");
|
||||||
Comparator<RequestKey> comparator = handlerMapping.getKeyComparator(request);
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
RequestKey key1 = new RequestKey(asList("/foo*"), null);
|
Comparator<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator(lookupPath, request);
|
||||||
RequestKey key2 = new RequestKey(asList("/foo*"), null);
|
RequestMappingKey key1 = new RequestMappingKey(asList("/foo*"), null);
|
||||||
|
RequestMappingKey key2 = new RequestMappingKey(asList("/foo*"), null);
|
||||||
|
|
||||||
assertEquals(0, comparator.compare(key1, key2));
|
assertEquals(0, comparator.compare(key1, key2));
|
||||||
}
|
}
|
||||||
|
|
@ -72,34 +75,35 @@ public class RequestKeyComparatorTests {
|
||||||
@Test
|
@Test
|
||||||
public void greaterNumberOfMatchingPatternsWins() throws Exception {
|
public void greaterNumberOfMatchingPatternsWins() throws Exception {
|
||||||
request.setRequestURI("/foo.html");
|
request.setRequestURI("/foo.html");
|
||||||
RequestKey key1 = new RequestKey(asList("/foo", "*.jpeg"), null);
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
RequestKey key2 = new RequestKey(asList("/foo", "*.html"), null);
|
RequestMappingKey key1 = new RequestMappingKey(asList("/foo", "*.jpeg"), null);
|
||||||
RequestKey match1 = handlerMapping.getMatchingKey(key1, request);
|
RequestMappingKey key2 = new RequestMappingKey(asList("/foo", "*.html"), null);
|
||||||
RequestKey match2 = handlerMapping.getMatchingKey(key2, request);
|
RequestMappingKey match1 = handlerMapping.getMatchingMappingKey(key1, lookupPath, request);
|
||||||
List<RequestKey> matches = asList(match1, match2);
|
RequestMappingKey match2 = handlerMapping.getMatchingMappingKey(key2, lookupPath, request);
|
||||||
Collections.sort(matches, handlerMapping.getKeyComparator(request));
|
List<RequestMappingKey> matches = asList(match1, match2);
|
||||||
|
Collections.sort(matches, handlerMapping.getMappingKeyComparator(lookupPath, request));
|
||||||
|
|
||||||
assertSame(match2.getPatterns(), matches.get(0).getPatterns());
|
assertSame(match2.getPatterns(), matches.get(0).getPatterns());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void oneMethodWinsOverNone() {
|
public void oneMethodWinsOverNone() {
|
||||||
Comparator<RequestKey> comparator = handlerMapping.getKeyComparator(request);
|
Comparator<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator("", request);
|
||||||
RequestKey key1 = new RequestKey(null, null);
|
RequestMappingKey key1 = new RequestMappingKey(null, null);
|
||||||
RequestKey key2 = new RequestKey(null, asList(RequestMethod.GET));
|
RequestMappingKey key2 = new RequestMappingKey(null, asList(RequestMethod.GET));
|
||||||
|
|
||||||
assertEquals(1, comparator.compare(key1, key2));
|
assertEquals(1, comparator.compare(key1, key2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void methodsAndParams() {
|
public void methodsAndParams() {
|
||||||
RequestKey empty = new RequestKey(null, null);
|
RequestMappingKey empty = new RequestMappingKey(null, null);
|
||||||
RequestKey oneMethod = new RequestKey(null, asList(RequestMethod.GET));
|
RequestMappingKey oneMethod = new RequestMappingKey(null, asList(RequestMethod.GET));
|
||||||
RequestKey oneMethodOneParam =
|
RequestMappingKey oneMethodOneParam =
|
||||||
new RequestKey(null, asList(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null);
|
new RequestMappingKey(null, asList(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null);
|
||||||
List<RequestKey> list = asList(empty, oneMethod, oneMethodOneParam);
|
List<RequestMappingKey> list = asList(empty, oneMethod, oneMethodOneParam);
|
||||||
Collections.shuffle(list);
|
Collections.shuffle(list);
|
||||||
Collections.sort(list, handlerMapping.getKeyComparator(request));
|
Collections.sort(list, handlerMapping.getMappingKeyComparator("", request));
|
||||||
|
|
||||||
assertEquals(oneMethodOneParam, list.get(0));
|
assertEquals(oneMethodOneParam, list.get(0));
|
||||||
assertEquals(oneMethod, list.get(1));
|
assertEquals(oneMethod, list.get(1));
|
||||||
|
|
@ -109,12 +113,12 @@ public class RequestKeyComparatorTests {
|
||||||
@Test
|
@Test
|
||||||
@Ignore // TODO : remove ignore
|
@Ignore // TODO : remove ignore
|
||||||
public void acceptHeaders() {
|
public void acceptHeaders() {
|
||||||
RequestKey html = new RequestKey(null, null, null, RequestConditionFactory.parseHeaders("accept=text/html"), null);
|
RequestMappingKey html = new RequestMappingKey(null, null, null, RequestConditionFactory.parseHeaders("accept=text/html"), null);
|
||||||
RequestKey xml = new RequestKey(null, null, null, RequestConditionFactory.parseHeaders("accept=application/xml"), null);
|
RequestMappingKey xml = new RequestMappingKey(null, null, null, RequestConditionFactory.parseHeaders("accept=application/xml"), null);
|
||||||
RequestKey none = new RequestKey(null, null);
|
RequestMappingKey none = new RequestMappingKey(null, null);
|
||||||
|
|
||||||
request.addHeader("Accept", "application/xml, text/html");
|
request.addHeader("Accept", "application/xml, text/html");
|
||||||
Comparator<RequestKey> comparator = handlerMapping.getKeyComparator(request);
|
Comparator<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator("", request);
|
||||||
|
|
||||||
assertTrue(comparator.compare(html, xml) > 0);
|
assertTrue(comparator.compare(html, xml) > 0);
|
||||||
assertTrue(comparator.compare(xml, html) < 0);
|
assertTrue(comparator.compare(xml, html) < 0);
|
||||||
|
|
@ -125,14 +129,14 @@ public class RequestKeyComparatorTests {
|
||||||
|
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest();
|
||||||
request.addHeader("Accept", "application/xml, text/*");
|
request.addHeader("Accept", "application/xml, text/*");
|
||||||
comparator = handlerMapping.getKeyComparator(request);
|
comparator = handlerMapping.getMappingKeyComparator("", request);
|
||||||
|
|
||||||
assertTrue(comparator.compare(html, xml) > 0);
|
assertTrue(comparator.compare(html, xml) > 0);
|
||||||
assertTrue(comparator.compare(xml, html) < 0);
|
assertTrue(comparator.compare(xml, html) < 0);
|
||||||
|
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest();
|
||||||
request.addHeader("Accept", "application/pdf");
|
request.addHeader("Accept", "application/pdf");
|
||||||
comparator = handlerMapping.getKeyComparator(request);
|
comparator = handlerMapping.getMappingKeyComparator("", request);
|
||||||
|
|
||||||
assertTrue(comparator.compare(html, xml) == 0);
|
assertTrue(comparator.compare(html, xml) == 0);
|
||||||
assertTrue(comparator.compare(xml, html) == 0);
|
assertTrue(comparator.compare(xml, html) == 0);
|
||||||
|
|
@ -140,7 +144,7 @@ public class RequestKeyComparatorTests {
|
||||||
// See SPR-7000
|
// See SPR-7000
|
||||||
request = new MockHttpServletRequest();
|
request = new MockHttpServletRequest();
|
||||||
request.addHeader("Accept", "text/html;q=0.9,application/xml");
|
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(html, xml) > 0);
|
||||||
assertTrue(comparator.compare(xml, html) < 0);
|
assertTrue(comparator.compare(xml, html) < 0);
|
||||||
|
|
|
||||||
|
|
@ -16,22 +16,23 @@
|
||||||
|
|
||||||
package org.springframework.web.servlet.mvc.method.annotation;
|
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.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.PathMatcher;
|
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.servlet.mvc.method.condition.RequestConditionFactory;
|
||||||
import org.springframework.web.util.UrlPathHelper;
|
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 Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
|
@ -40,8 +41,8 @@ public class RequestKeyTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void equals() {
|
public void equals() {
|
||||||
RequestKey key1 = new RequestKey(singleton("/foo"), singleton(GET));
|
RequestMappingKey key1 = new RequestMappingKey(singleton("/foo"), singleton(GET));
|
||||||
RequestKey key2 = new RequestKey(singleton("/foo"), singleton(GET));
|
RequestMappingKey key2 = new RequestMappingKey(singleton("/foo"), singleton(GET));
|
||||||
|
|
||||||
assertEquals(key1, key2);
|
assertEquals(key1, key2);
|
||||||
assertEquals(key1.hashCode(), key2.hashCode());
|
assertEquals(key1.hashCode(), key2.hashCode());
|
||||||
|
|
@ -49,8 +50,8 @@ public class RequestKeyTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void equalsPrependSlash() {
|
public void equalsPrependSlash() {
|
||||||
RequestKey key1 = new RequestKey(singleton("/foo"), singleton(GET));
|
RequestMappingKey key1 = new RequestMappingKey(singleton("/foo"), singleton(GET));
|
||||||
RequestKey key2 = new RequestKey(singleton("foo"), singleton(GET));
|
RequestMappingKey key2 = new RequestMappingKey(singleton("foo"), singleton(GET));
|
||||||
|
|
||||||
assertEquals(key1, key2);
|
assertEquals(key1, key2);
|
||||||
assertEquals(key1.hashCode(), key2.hashCode());
|
assertEquals(key1.hashCode(), key2.hashCode());
|
||||||
|
|
@ -60,9 +61,9 @@ public class RequestKeyTests {
|
||||||
public void combinePatterns() {
|
public void combinePatterns() {
|
||||||
AntPathMatcher pathMatcher = new AntPathMatcher();
|
AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||||
|
|
||||||
RequestKey key1 = createKeyFromPatterns("/t1", "/t2");
|
RequestMappingKey key1 = createKeyFromPatterns("/t1", "/t2");
|
||||||
RequestKey key2 = createKeyFromPatterns("/m1", "/m2");
|
RequestMappingKey key2 = createKeyFromPatterns("/m1", "/m2");
|
||||||
RequestKey key3 = createKeyFromPatterns("/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2");
|
RequestMappingKey key3 = createKeyFromPatterns("/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2");
|
||||||
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
|
assertEquals(key3.getPatterns(), key1.combine(key2, pathMatcher).getPatterns());
|
||||||
|
|
||||||
key1 = createKeyFromPatterns("/t1");
|
key1 = createKeyFromPatterns("/t1");
|
||||||
|
|
@ -88,154 +89,147 @@ public class RequestKeyTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void matchPatternsToRequest() {
|
public void matchPatternsToRequest() {
|
||||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
UrlPathHelper pathHelper = new UrlPathHelper();
|
||||||
PathMatcher pathMatcher = new AntPathMatcher();
|
PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
|
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
RequestKey key = new RequestKey(singleton("/foo"), null);
|
RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null);
|
||||||
RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
RequestMappingKey match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull(match);
|
assertNotNull(match);
|
||||||
|
|
||||||
request = new MockHttpServletRequest("GET", "/foo/bar");
|
request = new MockHttpServletRequest("GET", "/foo/bar");
|
||||||
key = new RequestKey(singleton("/foo/*"), null);
|
key = new RequestMappingKey(singleton("/foo/*"), null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull("Pattern match", match);
|
assertNotNull("Pattern match", match);
|
||||||
|
|
||||||
request = new MockHttpServletRequest("GET", "/foo.html");
|
request = new MockHttpServletRequest("GET", "/foo.html");
|
||||||
key = new RequestKey(singleton("/foo"), null);
|
key = new RequestMappingKey(singleton("/foo"), null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull("Implicit match by extension", match);
|
assertNotNull("Implicit match by extension", match);
|
||||||
assertEquals("Contains matched pattern", "/foo.*", match.getPatterns().iterator().next());
|
assertEquals("Contains matched pattern", "/foo.*", match.getPatterns().iterator().next());
|
||||||
|
|
||||||
request = new MockHttpServletRequest("GET", "/foo/");
|
request = new MockHttpServletRequest("GET", "/foo/");
|
||||||
key = new RequestKey(singleton("/foo"), null);
|
key = new RequestMappingKey(singleton("/foo"), null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull("Implicit match by trailing slash", match);
|
assertNotNull("Implicit match by trailing slash", match);
|
||||||
assertEquals("Contains matched pattern", "/foo/", match.getPatterns().iterator().next());
|
assertEquals("Contains matched pattern", "/foo/", match.getPatterns().iterator().next());
|
||||||
|
|
||||||
request = new MockHttpServletRequest("GET", "/foo.html");
|
request = new MockHttpServletRequest("GET", "/foo.html");
|
||||||
key = new RequestKey(singleton("/foo.jpg"), null);
|
key = new RequestMappingKey(singleton("/foo.jpg"), null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||||
|
|
||||||
assertNull("Implicit match ignored if pattern has extension", match);
|
assertNull("Implicit match ignored if pattern has extension", match);
|
||||||
|
|
||||||
request = new MockHttpServletRequest("GET", "/foo.html");
|
request = new MockHttpServletRequest("GET", "/foo.html");
|
||||||
key = new RequestKey(singleton("/foo.jpg"), null);
|
key = new RequestMappingKey(singleton("/foo.jpg"), null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
|
||||||
|
|
||||||
assertNull("Implicit match ignored on pattern with trailing slash", match);
|
assertNull("Implicit match ignored on pattern with trailing slash", match);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void matchRequestMethods() {
|
public void matchRequestMethods() {
|
||||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
PathMatcher pathMatcher = new AntPathMatcher();
|
PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
|
|
||||||
RequestKey key = new RequestKey(singleton("/foo"), null);
|
RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null);
|
||||||
RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull("No method matches any method", match);
|
assertNotNull("No method matches any method", match);
|
||||||
|
|
||||||
key = new RequestKey(singleton("/foo"), singleton(GET));
|
key = new RequestMappingKey(singleton("/foo"), singleton(GET));
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull("Exact match", match);
|
assertNotNull("Exact match", match);
|
||||||
|
|
||||||
key = new RequestKey(singleton("/foo"), singleton(POST));
|
key = new RequestMappingKey(singleton("/foo"), singleton(POST));
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNull("No match", match);
|
assertNull("No match", match);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void matchingKeyContent() {
|
public void matchingKeyContent() {
|
||||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
PathMatcher pathMatcher = new AntPathMatcher();
|
PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
|
|
||||||
RequestKey key = new RequestKey(asList("/foo*", "/bar"), asList(GET, POST));
|
RequestMappingKey key = new RequestMappingKey(asList("/foo*", "/bar"), asList(GET, POST));
|
||||||
RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
RequestKey expected = new RequestKey(singleton("/foo*"), singleton(GET));
|
RequestMappingKey expected = new RequestMappingKey(singleton("/foo*"), singleton(GET));
|
||||||
|
|
||||||
assertEquals("Matching RequestKey contains matched patterns and methods only", expected, match);
|
assertEquals("Matching RequestKey contains matched patterns and methods only", expected, match);
|
||||||
|
|
||||||
key = new RequestKey(asList("/**", "/foo*", "/foo"), null);
|
key = new RequestMappingKey(asList("/**", "/foo*", "/foo"), null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
expected = new RequestKey(asList("/foo", "/foo*", "/**"), null);
|
expected = new RequestMappingKey(asList("/foo", "/foo*", "/**"), null);
|
||||||
|
|
||||||
assertEquals("Matched patterns are sorted with best match at the top", expected, match);
|
assertEquals("Matched patterns are sorted with best match at the top", expected, match);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void paramsCondition() {
|
public void paramsCondition() {
|
||||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
PathMatcher pathMatcher = new AntPathMatcher();
|
PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
request.setParameter("foo", "bar");
|
request.setParameter("foo", "bar");
|
||||||
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
|
|
||||||
RequestKey key = new RequestKey(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null, null);
|
RequestMappingKey key = new RequestMappingKey(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null, null);
|
||||||
RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull(match);
|
assertNotNull(match);
|
||||||
|
|
||||||
key = new RequestKey(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null, null);
|
key = new RequestMappingKey(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null, null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNull(match);
|
assertNull(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void headersCondition() {
|
public void headersCondition() {
|
||||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
PathMatcher pathMatcher = new AntPathMatcher();
|
PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
request.addHeader("foo", "bar");
|
request.addHeader("foo", "bar");
|
||||||
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
|
|
||||||
RequestKey key = new RequestKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"), null);
|
RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"), null);
|
||||||
RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull(match);
|
assertNotNull(match);
|
||||||
|
|
||||||
key = new RequestKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"), null);
|
key = new RequestMappingKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"), null);
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNull(match);
|
assertNull(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void consumesCondition() {
|
public void consumesCondition() {
|
||||||
UrlPathHelper urlPathHelper = new UrlPathHelper();
|
|
||||||
PathMatcher pathMatcher = new AntPathMatcher();
|
PathMatcher pathMatcher = new AntPathMatcher();
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
request.setContentType("text/plain");
|
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"));
|
"text/plain"));
|
||||||
RequestKey match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNotNull(match);
|
assertNotNull(match);
|
||||||
|
|
||||||
key = new RequestKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
|
key = new RequestMappingKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
|
||||||
"application/xml"));
|
"application/xml"));
|
||||||
match = key.getMatchingKey(request, pathMatcher, urlPathHelper);
|
match = key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||||
|
|
||||||
assertNull(match);
|
assertNull(match);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private RequestMappingKey createKeyFromPatterns(String... patterns) {
|
||||||
public void createFromServletRequest() {
|
return new RequestMappingKey(asList(patterns), null);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +27,6 @@ import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.context.support.StaticApplicationContext;
|
import org.springframework.context.support.StaticApplicationContext;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
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.HandlerMapping;
|
||||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||||
import org.springframework.web.servlet.handler.MappedInterceptor;
|
import org.springframework.web.servlet.handler.MappedInterceptor;
|
||||||
|
import org.springframework.web.util.UrlPathHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test fixture with {@link RequestMappingHandlerMethodMapping}.
|
* Test fixture with {@link RequestMappingHandlerMethodMapping}.
|
||||||
|
|
@ -102,8 +102,6 @@ public class RequestMappingHandlerMethodMappingTests {
|
||||||
assertEquals(emptyMethod.getMethod(), hm.getMethod());
|
assertEquals(emptyMethod.getMethod(), hm.getMethod());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: SPR-8247
|
|
||||||
@Ignore
|
|
||||||
@Test
|
@Test
|
||||||
public void bestMatch() throws Exception {
|
public void bestMatch() throws Exception {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||||
|
|
@ -126,10 +124,11 @@ public class RequestMappingHandlerMethodMappingTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void uriTemplateVariables() {
|
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");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/1/2");
|
||||||
|
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
|
||||||
|
|
||||||
mapping.handleMatch(key, request);
|
mapping.handleMatch(key, lookupPath, request);
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Map<String, String> actual = (Map<String, String>) request.getAttribute(
|
Map<String, String> actual = (Map<String, String>) request.getAttribute(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue