SPR-8247 review changes

This commit is contained in:
Rossen Stoyanchev 2011-04-21 11:40:24 +00:00
parent ab654a7a06
commit acb9433e5c
8 changed files with 198 additions and 211 deletions

View File

@ -41,7 +41,7 @@ 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.
* *
* @param <T> Represents a mapping key with conditions for mapping a request to a {@link HandlerMethod}. * @param <T> A type containing request mapping conditions required to match a request to a {@link HandlerMethod}.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
@ -106,7 +106,7 @@ 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 mapping for a handler is up to the concrete {@link #getMappingKeyForMethod(String, Method)} * <p>The actual mapping for a handler is up to the concrete {@link #getMappingForMethod(String, Method)}
* implementation. * implementation.
*/ */
protected void initHandlerMethods() { protected void initHandlerMethods() {
@ -135,57 +135,57 @@ 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 getMappingKeyForMethod(beanName, method) != null; return getMappingForMethod(beanName, method) != null;
} }
}); });
for (Method method : methods) { for (Method method : methods) {
HandlerMethod handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method); HandlerMethod handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
T mapping = getMappingKeyForMethod(beanName, method); T mapping = getMappingForMethod(beanName, method);
Set<String> paths = getMappingPaths(mapping); Set<String> paths = getMappingPaths(mapping);
registerHandlerMethod(paths, mapping, handlerMethod); registerHandlerMethod(paths, mapping, handlerMethod);
} }
} }
/** /**
* Provides a mapping key for the given bean method. A method for which no mapping can be determined is * Provides a request mapping for the given bean method. A method for which no request mapping can be determined
* not considered a handler method. * is 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 mapping for * @param method the method to create a mapping for
* @return the mapping key, or {@code null} if the method is not mapped * @return the mapping, or {@code null} if the method is not mapped
*/ */
protected abstract T getMappingKeyForMethod(String beanName, Method method); protected abstract T getMappingForMethod(String beanName, Method method);
/** /**
* Registers a {@link HandlerMethod} with the given mapping. * Registers a {@link HandlerMethod} with the given mapping.
* *
* @param paths URL paths mapped to this method * @param paths URL paths mapped to this method
* @param mappingKey the mapping key for the method * @param mapping the mapping 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 same mapping * @throws IllegalStateException if another method was already register under the same mapping
*/ */
protected void registerHandlerMethod(Set<String> paths, T mappingKey, HandlerMethod handlerMethod) { protected void registerHandlerMethod(Set<String> paths, T mapping, HandlerMethod handlerMethod) {
Assert.notNull(mappingKey, "'mapping' must not be null"); Assert.notNull(mapping, "'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(mappingKey); HandlerMethod mappedHandlerMethod = handlerMethods.get(mapping);
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 " + mappingKey + ": There is already '" + "' bean method \n" + handlerMethod + "\nto " + mapping + ": There is already '"
+ mappedHandlerMethod.getBean() + "' bean method\n" + mappedHandlerMethod + " mapped."); + mappedHandlerMethod.getBean() + "' bean method\n" + mappedHandlerMethod + " mapped.");
} }
handlerMethods.put(mappingKey, handlerMethod); handlerMethods.put(mapping, handlerMethod);
if (logger.isInfoEnabled()) { if (logger.isInfoEnabled()) {
logger.info("Mapped \"" + mappingKey + "\" onto " + handlerMethod); logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
} }
for (String path : paths) { for (String path : paths) {
urlMap.add(path, mappingKey); urlMap.add(path, mapping);
} }
} }
/** /**
* Get the URL paths for the given mapping. * Get the URL paths for the given mapping.
*/ */
protected abstract Set<String> getMappingPaths(T mappingKey); protected abstract Set<String> getMappingPaths(T mapping);
@Override @Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
@ -211,32 +211,32 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
/** /**
* Looks up the best-matching {@link HandlerMethod} for the given request. * Looks up the best-matching {@link HandlerMethod} for the given request.
* *
* <p>This implementation iterators through all handler methods, calls {@link #getMatchingKey(Object, * <p>This implementation iterators through all handler methods, calls
* HttpServletRequest)} for each of them, {@linkplain #getKeyComparator(HttpServletRequest) sorts} all matches, and * {@link #getMatchingMapping(Object, String, HttpServletRequest)} for each of them,
* returns the 1st entry, if any. If no matches are found, {@link #handleNoMatch(Set, HttpServletRequest)} is * sorts all matches via {@linkplain #getMappingComparator(String, HttpServletRequest)} , and returns the
* invoked. * top match, if any. If no matches are found, {@link #handleNoMatch(Set, HttpServletRequest)} is invoked.
* *
* @param lookupPath mapping lookup path within the current servlet mapping if applicable * @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(String lookupPath, HttpServletRequest request) throws Exception { protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<T> keys = urlMap.get(lookupPath); List<T> mappings = urlMap.get(lookupPath);
if (keys == null) { if (mappings == null) {
keys = new ArrayList<T>(handlerMethods.keySet()); mappings = new ArrayList<T>(handlerMethods.keySet());
} }
List<Match> matches = new ArrayList<Match>(); List<Match> matches = new ArrayList<Match>();
for (T key : keys) { for (T mapping : mappings) {
T match = getMatchingMappingKey(key, lookupPath, request); T match = getMatchingMapping(mapping, lookupPath, request);
if (match != null) { if (match != null) {
matches.add(new Match(match, handlerMethods.get(key))); matches.add(new Match(match, handlerMethods.get(mapping)));
} }
} }
if (!matches.isEmpty()) { if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingKeyComparator(lookupPath, request)); Comparator<Match> comparator = new MatchComparator(getMappingComparator(lookupPath, request));
Collections.sort(matches, comparator); Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {
@ -255,7 +255,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
} }
} }
handleMatch(bestMatch.mappingKey, lookupPath, request); handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod; return bestMatch.handlerMethod;
} }
else { else {
@ -266,12 +266,12 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
/** /**
* Invoked when a request has been matched to a mapping. * Invoked when a request has been matched to a mapping.
* *
* @param mappingKey the mapping selected for the request returned by * @param mapping the mapping selected for the request returned by
* {@link #getMatchingMappingKey(Object, String, HttpServletRequest)}. * {@link #getMatchingMapping(Object, String, HttpServletRequest)}.
* @param lookupPath mapping lookup path within the current servlet mapping if applicable * @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 mappingKey, String lookupPath, HttpServletRequest request) { protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) {
} }
/** /**
@ -279,49 +279,49 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
* relevant to the current request (for example a mapping may have several HTTP methods, the matching mapping * relevant to the current request (for example a mapping may have several HTTP methods, the matching mapping
* will contain only 1). * will contain only 1).
* *
* @param mappingKey the mapping key to get a match for * @param mapping the mapping to get a match for
* @param lookupPath mapping lookup path within the current servlet mapping if applicable * @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 a matching mapping, or {@code null} if the given mapping does not match the request * @return a matching mapping, or {@code null} if the given mapping does not match the request
*/ */
protected abstract T getMatchingMappingKey(T mappingKey, String lookupPath, HttpServletRequest request); protected abstract T getMatchingMapping(T mapping, String lookupPath, HttpServletRequest request);
/** /**
* Returns a comparator to sort mapping keys with. The returned comparator should sort 'better' matches higher. * Returns a comparator to sort request mappings with. The returned comparator should sort 'better' matches higher.
* *
* @param lookupPath mapping lookup path within the current servlet mapping if applicable * @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> getMappingKeyComparator(String lookupPath, HttpServletRequest request); protected abstract Comparator<T> getMappingComparator(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 mappingKeys all registered mappings * @param mappings all registered request mappings
* @param lookupPath mapping lookup path within the current servlet mapping if applicable * @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> mappingKeys, String lookupPath, HttpServletRequest request) protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request)
throws Exception { throws Exception {
return null; return null;
} }
private class Match { private class Match {
private final T mappingKey; private final T mapping;
private final HandlerMethod handlerMethod; private final HandlerMethod handlerMethod;
private Match(T mapping, HandlerMethod handlerMethod) { private Match(T mapping, HandlerMethod handlerMethod) {
this.mappingKey = mapping; this.mapping = mapping;
this.handlerMethod = handlerMethod; this.handlerMethod = handlerMethod;
} }
@Override @Override
public String toString() { public String toString() {
return mappingKey.toString(); return mapping.toString();
} }
} }
@ -334,7 +334,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
} }
public int compare(Match match1, Match match2) { public int compare(Match match1, Match match2) {
return comparator.compare(match1.mappingKey, match2.mappingKey); return comparator.compare(match1.mapping, match2.mapping);
} }
} }

View File

@ -46,14 +46,14 @@ import org.springframework.web.servlet.handler.MappedInterceptors;
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory; import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
/** /**
* An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingKey}s for the registration and * An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingInfo}s for the registration and
* the lookup of {@link HandlerMethod}s. * the lookup of {@link HandlerMethod}s.
* *
* @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<RequestMappingKey> { public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
private PathMatcher pathMatcher = new AntPathMatcher(); private PathMatcher pathMatcher = new AntPathMatcher();
@ -97,28 +97,28 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
} }
/** /**
* Provides a {@link RequestMappingKey} for the given method. * Provides a {@link RequestMappingInfo} 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.
* *
* @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 key, or {@code null} * @return the mapping, or {@code null}
* @see RequestMappingKey#combine(RequestMappingKey, PathMatcher) * @see RequestMappingInfo#combine(RequestMappingInfo, PathMatcher)
*/ */
@Override @Override
protected RequestMappingKey getMappingKeyForMethod(String beanName, Method method) { protected RequestMappingInfo getMappingForMethod(String beanName, Method method) {
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class); RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
if (annotation != null) { if (annotation != null) {
RequestMappingKey methodKey = createFromRequestMapping(annotation); RequestMappingInfo methodMapping = createFromRequestMapping(annotation);
RequestMapping typeAnnot = getApplicationContext().findAnnotationOnBean(beanName, RequestMapping.class); RequestMapping typeAnnot = getApplicationContext().findAnnotationOnBean(beanName, RequestMapping.class);
if (typeAnnot != null) { if (typeAnnot != null) {
RequestMappingKey typeKey = createFromRequestMapping(typeAnnot); RequestMappingInfo typeMapping = createFromRequestMapping(typeAnnot);
return typeKey.combine(methodKey, pathMatcher); return typeMapping.combine(methodMapping, pathMatcher);
} }
else { else {
return methodKey; return methodMapping;
} }
} }
else { else {
@ -126,55 +126,53 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
} }
} }
private static RequestMappingKey createFromRequestMapping(RequestMapping annotation) { private static RequestMappingInfo createFromRequestMapping(RequestMapping annotation) {
return new RequestMappingKey(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()), return new RequestMappingInfo(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()),
RequestConditionFactory.parseParams(annotation.params()), RequestConditionFactory.parseParams(annotation.params()),
RequestConditionFactory.parseHeaders(annotation.headers()), RequestConditionFactory.parseHeaders(annotation.headers()));
RequestConditionFactory.parseConsumes(annotation.consumes())
);
} }
@Override @Override
protected Set<String> getMappingPaths(RequestMappingKey key) { protected Set<String> getMappingPaths(RequestMappingInfo mapping) {
return key.getPatterns(); return mapping.getPatterns();
} }
/** /**
* Returns a new {@link RequestMappingKey} with attributes matching to the current request or {@code null}. * Returns a new {@link RequestMappingInfo} with attributes matching to the current request or {@code null}.
* @see RequestMappingKey#getMatchingKey(String, HttpServletRequest, PathMatcher) * @see RequestMappingInfo#getMatchingRequestMapping(String, HttpServletRequest, PathMatcher)
*/ */
@Override @Override
protected RequestMappingKey getMatchingMappingKey(RequestMappingKey key, String lookupPath, HttpServletRequest request) { protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping, String lookupPath, HttpServletRequest request) {
return key.getMatchingKey(lookupPath, request, pathMatcher); return mapping.getMatchingRequestMapping(lookupPath, request, pathMatcher);
} }
/** /**
* Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestMappingKey}. * Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestMappingInfo}.
*/ */
@Override @Override
protected Comparator<RequestMappingKey> getMappingKeyComparator(String lookupPath, HttpServletRequest request) { protected Comparator<RequestMappingInfo> getMappingComparator(String lookupPath, HttpServletRequest request) {
return new RequestKeyComparator(lookupPath, request); return new RequestMappingInfoComparator(lookupPath, request);
} }
@Override @Override
protected void handleMatch(RequestMappingKey key, String lookupPath, HttpServletRequest request) { protected void handleMatch(RequestMappingInfo mapping, String lookupPath, HttpServletRequest request) {
String pattern = key.getPatterns().iterator().next(); String pattern = mapping.getPatterns().iterator().next();
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 RequestMappingKey}s looking for keys that match by URL but not by HTTP method. * Iterates all {@link RequestMappingInfo}s looking for mappings 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<RequestMappingKey> requestKeys, String lookupPath, HttpServletRequest request) protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos, String lookupPath, HttpServletRequest request)
throws HttpRequestMethodNotSupportedException { throws HttpRequestMethodNotSupportedException {
Set<String> allowedMethods = new HashSet<String>(6); Set<String> allowedMethods = new HashSet<String>(6);
for (RequestMappingKey requestKey : requestKeys) { for (RequestMappingInfo info : requestMappingInfos) {
for (String pattern : requestKey.getPatterns()) { for (String pattern : info.getPatterns()) {
if (pathMatcher.match(pattern, lookupPath)) { if (pathMatcher.match(pattern, lookupPath)) {
for (RequestMethod method : requestKey.getMethods()) { for (RequestMethod method : info.getMethods()) {
allowedMethods.add(method.name()); allowedMethods.add(method.name());
} }
} }
@ -206,50 +204,50 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
} }
/** /**
* A comparator for {@link RequestMappingKey}s. Effective comparison can only be done in the context of a * A comparator for {@link RequestMappingInfo}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. * specific request. For example not all {@link RequestMappingInfo} 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 RequestMappings:
* <ul><li>Each RequestKey has been fully matched to the request <li>The RequestKey contains matched * <ul><li>Each RequestMappingInfo has been fully matched to the request <li>The RequestMappingInfo contains
* patterns only <li>Patterns are ordered with the best matching pattern at the top </ul> * matched patterns only <li>Patterns are ordered with the best matching pattern at the top </ul>
* *
* @see RequestMappingHandlerMethodMapping#getMatchingKey(RequestMappingKey, HttpServletRequest) * @see RequestMappingHandlerMethodMapping#getMatchingMapping(RequestMappingInfo, String, HttpServletRequest)
*/ */
private class RequestKeyComparator implements Comparator<RequestMappingKey> { private class RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {
private Comparator<String> patternComparator; private Comparator<String> patternComparator;
private List<MediaType> requestAcceptHeader; private List<MediaType> requestAcceptHeader;
public RequestKeyComparator(String lookupPath, HttpServletRequest request) { public RequestMappingInfoComparator(String lookupPath, HttpServletRequest 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(RequestMappingKey key, RequestMappingKey otherKey) { public int compare(RequestMappingInfo mapping, RequestMappingInfo otherMapping) {
int result = comparePatterns(key.getPatterns(), otherKey.getPatterns()); int result = comparePatterns(mapping.getPatterns(), otherMapping.getPatterns());
if (result != 0) { if (result != 0) {
return result; return result;
} }
result = key.getParams().compareTo(otherKey.getParams()); result = mapping.getParams().compareTo(otherMapping.getParams());
if (result != 0) { if (result != 0) {
return result; return result;
} }
result = key.getHeaders().compareTo(otherKey.getHeaders()); result = mapping.getHeaders().compareTo(otherMapping.getHeaders());
if (result != 0) { if (result != 0) {
return result; return result;
} }
/* /*
TODO: fix TODO: fix
result = compareAcceptHeaders(key.getAcceptHeaderMediaTypes(), otherKey.getAcceptHeaderMediaTypes()); result = compareAcceptHeaders(mapping.getAcceptHeaderMediaTypes(), otherMapping.getAcceptHeaderMediaTypes());
if (result != 0) { if (result != 0) {
return result; return result;
} }
*/ */
result = otherKey.getMethods().size() - key.getMethods().size(); result = otherMapping.getMethods().size() - mapping.getMethods().size();
if (result != 0) { if (result != 0) {
return result; return result;
} }

View File

@ -32,20 +32,18 @@ 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;
/** /**
* 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
* parameters and headers. * and headers.
* *
* <p>A {@link RequestMappingKey} can be combined with another {@link RequestMappingKey} resulting in a new {@link RequestMappingKey} * <p>Two {@link RequestMappingInfo}s can be combined resulting in a new {@link RequestMappingInfo} with conditions
* with conditions from both (see {@link #combine(RequestMappingKey, PathMatcher)}). * from both. A {@link RequestMappingInfo} can also match itself to an HTTP request resulting in a new
* * {@link RequestMappingInfo} with the subset of conditions relevant to the request.
* <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(String, HttpServletRequest, PathMatcher)}).
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 3.1 * @since 3.1
*/ */
public final class RequestMappingKey { public final class RequestMappingInfo {
private final Set<String> patterns; private final Set<String> patterns;
@ -55,8 +53,6 @@ public final class RequestMappingKey {
private final RequestCondition headersCondition; private final RequestCondition headersCondition;
private final RequestCondition consumesCondition;
private int hash; private int hash;
/** /**
@ -64,23 +60,21 @@ public final class RequestMappingKey {
* *
* <p>Package protected for testing purposes. * <p>Package protected for testing purposes.
*/ */
RequestMappingKey(Collection<String> patterns, Collection<RequestMethod> methods) { RequestMappingInfo(Collection<String> patterns, Collection<RequestMethod> methods) {
this(patterns, methods, null, null, null); this(patterns, methods, 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.
*/ */
public RequestMappingKey(Collection<String> patterns, public RequestMappingInfo(Collection<String> patterns,
Collection<RequestMethod> methods, Collection<RequestMethod> methods,
RequestCondition paramsCondition, RequestCondition paramsCondition,
RequestCondition headersCondition, RequestCondition headersCondition) {
RequestCondition consumesCondition) {
this.patterns = asUnmodifiableSet(prependLeadingSlash(patterns)); this.patterns = asUnmodifiableSet(prependLeadingSlash(patterns));
this.methods = asUnmodifiableSet(methods); this.methods = asUnmodifiableSet(methods);
this.paramsCondition = paramsCondition != null ? paramsCondition : RequestConditionFactory.trueCondition(); this.paramsCondition = paramsCondition != null ? paramsCondition : RequestConditionFactory.trueCondition();
this.headersCondition = headersCondition != null ? headersCondition : RequestConditionFactory.trueCondition(); this.headersCondition = headersCondition != null ? headersCondition : RequestConditionFactory.trueCondition();
this.consumesCondition = consumesCondition != null ? consumesCondition : RequestConditionFactory.trueCondition();
} }
private static Set<String> prependLeadingSlash(Collection<String> patterns) { private static Set<String> prependLeadingSlash(Collection<String> patterns) {
@ -145,20 +139,18 @@ public final class RequestMappingKey {
* <li>HTTP methods are combined as union of all HTTP methods listed in both keys. * <li>HTTP methods are combined as union of all HTTP methods listed in both keys.
* <li>Request parameter are combined into a logical AND. * <li>Request parameter are combined into a logical AND.
* <li>Request header are combined into a logical AND. * <li>Request header are combined into a logical AND.
* <li>Consumes .. TODO
* </ul> * </ul>
* @param methodKey the key to combine with * @param methodKey the key to combine with
* @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 RequestMappingKey combine(RequestMappingKey methodKey, PathMatcher pathMatcher) { public RequestMappingInfo combine(RequestMappingInfo 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);
return new RequestMappingKey(patterns, methods, params, headers, consumes); return new RequestMappingInfo(patterns, methods, params, headers);
} }
private static Set<String> combinePatterns(Collection<String> typePatterns, private static Set<String> combinePatterns(Collection<String> typePatterns,
@ -204,17 +196,15 @@ public final class RequestMappingKey {
* @param pathMatcher to check for matching patterns * @param pathMatcher to check for matching patterns
* @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 RequestMappingKey getMatchingKey(String lookupPath, HttpServletRequest request, PathMatcher pathMatcher) { public RequestMappingInfo getMatchingRequestMapping(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)) {
return null; return null;
} }
else { else {
List<String> matchingPatterns = getMatchingPatterns(lookupPath, request, pathMatcher); 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 RequestMappingKey(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition, return new RequestMappingInfo(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition);
this.consumesCondition);
} }
else { else {
return null; return null;
@ -275,8 +265,8 @@ public final class RequestMappingKey {
if (this == obj) { if (this == obj) {
return true; return true;
} }
if (obj != null && obj instanceof RequestMappingKey) { if (obj != null && obj instanceof RequestMappingInfo) {
RequestMappingKey other = (RequestMappingKey) obj; RequestMappingInfo other = (RequestMappingInfo) 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));
@ -307,7 +297,6 @@ public final class RequestMappingKey {
} }
builder.append(",params=").append(paramsCondition.toString()); builder.append(",params=").append(paramsCondition.toString());
builder.append(",headers=").append(headersCondition.toString()); builder.append(",headers=").append(headersCondition.toString());
builder.append(",consumes=").append(consumesCondition.toString());
builder.append('}'); builder.append('}');
return builder.toString(); return builder.toString();
} }

View File

@ -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.RequestMappingKey RequestKey}. * org.springframework.web.servlet.mvc.method.annotation.RequestMappingInfo RequestKey}.
* *
* <p>Implementations of this interface are created by the {@link RequestConditionFactory}. * <p>Implementations of this interface are created by the {@link RequestConditionFactory}.
* *

View File

@ -90,18 +90,18 @@ public class HandlerMethodMappingTests {
private PathMatcher pathMatcher = new AntPathMatcher(); private PathMatcher pathMatcher = new AntPathMatcher();
@Override @Override
protected String getMatchingMappingKey(String pattern, String lookupPath, HttpServletRequest request) { protected String getMatchingMapping(String pattern, String lookupPath, HttpServletRequest request) {
return pathMatcher.match(pattern, lookupPath) ? pattern : null; return pathMatcher.match(pattern, lookupPath) ? pattern : null;
} }
@Override @Override
protected String getMappingKeyForMethod(String beanName, Method method) { protected String getMappingForMethod(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> getMappingKeyComparator(String lookupPath, HttpServletRequest request) { protected Comparator<String> getMappingComparator(String lookupPath, HttpServletRequest request) {
return pathMatcher.getPatternComparator(lookupPath); return pathMatcher.getPatternComparator(lookupPath);
} }

View File

@ -33,7 +33,7 @@ import static java.util.Arrays.*;
import static org.junit.Assert.*; import static org.junit.Assert.*;
/** /**
* Test fixture with {@link RequestMappingHandlerMethodMapping} testing its {@link RequestMappingKey} comparator. * Test fixture with {@link RequestMappingHandlerMethodMapping} testing its {@link RequestMappingInfo} comparator.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
@ -54,9 +54,9 @@ public class RequestKeyComparatorTests {
public void moreSpecificPatternWins() { public void moreSpecificPatternWins() {
request.setRequestURI("/foo"); request.setRequestURI("/foo");
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
Comparator<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator(lookupPath, request); Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator(lookupPath, request);
RequestMappingKey key1 = new RequestMappingKey(asList("/fo*"), null); RequestMappingInfo key1 = new RequestMappingInfo(asList("/fo*"), null);
RequestMappingKey key2 = new RequestMappingKey(asList("/foo"), null); RequestMappingInfo key2 = new RequestMappingInfo(asList("/foo"), null);
assertEquals(1, comparator.compare(key1, key2)); assertEquals(1, comparator.compare(key1, key2));
} }
@ -65,9 +65,9 @@ public class RequestKeyComparatorTests {
public void equalPatterns() { public void equalPatterns() {
request.setRequestURI("/foo"); request.setRequestURI("/foo");
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
Comparator<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator(lookupPath, request); Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator(lookupPath, request);
RequestMappingKey key1 = new RequestMappingKey(asList("/foo*"), null); RequestMappingInfo key1 = new RequestMappingInfo(asList("/foo*"), null);
RequestMappingKey key2 = new RequestMappingKey(asList("/foo*"), null); RequestMappingInfo key2 = new RequestMappingInfo(asList("/foo*"), null);
assertEquals(0, comparator.compare(key1, key2)); assertEquals(0, comparator.compare(key1, key2));
} }
@ -76,34 +76,34 @@ public class RequestKeyComparatorTests {
public void greaterNumberOfMatchingPatternsWins() throws Exception { public void greaterNumberOfMatchingPatternsWins() throws Exception {
request.setRequestURI("/foo.html"); request.setRequestURI("/foo.html");
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
RequestMappingKey key1 = new RequestMappingKey(asList("/foo", "*.jpeg"), null); RequestMappingInfo key1 = new RequestMappingInfo(asList("/foo", "*.jpeg"), null);
RequestMappingKey key2 = new RequestMappingKey(asList("/foo", "*.html"), null); RequestMappingInfo key2 = new RequestMappingInfo(asList("/foo", "*.html"), null);
RequestMappingKey match1 = handlerMapping.getMatchingMappingKey(key1, lookupPath, request); RequestMappingInfo match1 = handlerMapping.getMatchingMapping(key1, lookupPath, request);
RequestMappingKey match2 = handlerMapping.getMatchingMappingKey(key2, lookupPath, request); RequestMappingInfo match2 = handlerMapping.getMatchingMapping(key2, lookupPath, request);
List<RequestMappingKey> matches = asList(match1, match2); List<RequestMappingInfo> matches = asList(match1, match2);
Collections.sort(matches, handlerMapping.getMappingKeyComparator(lookupPath, request)); Collections.sort(matches, handlerMapping.getMappingComparator(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<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator("", request); Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator("", request);
RequestMappingKey key1 = new RequestMappingKey(null, null); RequestMappingInfo key1 = new RequestMappingInfo(null, null);
RequestMappingKey key2 = new RequestMappingKey(null, asList(RequestMethod.GET)); RequestMappingInfo key2 = new RequestMappingInfo(null, asList(RequestMethod.GET));
assertEquals(1, comparator.compare(key1, key2)); assertEquals(1, comparator.compare(key1, key2));
} }
@Test @Test
public void methodsAndParams() { public void methodsAndParams() {
RequestMappingKey empty = new RequestMappingKey(null, null); RequestMappingInfo empty = new RequestMappingInfo(null, null);
RequestMappingKey oneMethod = new RequestMappingKey(null, asList(RequestMethod.GET)); RequestMappingInfo oneMethod = new RequestMappingInfo(null, asList(RequestMethod.GET));
RequestMappingKey oneMethodOneParam = RequestMappingInfo oneMethodOneParam =
new RequestMappingKey(null, asList(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null, null); new RequestMappingInfo(null, asList(RequestMethod.GET), RequestConditionFactory.parseParams("foo"), null);
List<RequestMappingKey> list = asList(empty, oneMethod, oneMethodOneParam); List<RequestMappingInfo> list = asList(empty, oneMethod, oneMethodOneParam);
Collections.shuffle(list); Collections.shuffle(list);
Collections.sort(list, handlerMapping.getMappingKeyComparator("", request)); Collections.sort(list, handlerMapping.getMappingComparator("", request));
assertEquals(oneMethodOneParam, list.get(0)); assertEquals(oneMethodOneParam, list.get(0));
assertEquals(oneMethod, list.get(1)); assertEquals(oneMethod, list.get(1));
@ -113,12 +113,12 @@ public class RequestKeyComparatorTests {
@Test @Test
@Ignore // TODO : remove ignore @Ignore // TODO : remove ignore
public void acceptHeaders() { public void acceptHeaders() {
RequestMappingKey html = new RequestMappingKey(null, null, null, RequestConditionFactory.parseHeaders("accept=text/html"), null); RequestMappingInfo html = new RequestMappingInfo(null, null, null, RequestConditionFactory.parseHeaders("accept=text/html"));
RequestMappingKey xml = new RequestMappingKey(null, null, null, RequestConditionFactory.parseHeaders("accept=application/xml"), null); RequestMappingInfo xml = new RequestMappingInfo(null, null, null, RequestConditionFactory.parseHeaders("accept=application/xml"));
RequestMappingKey none = new RequestMappingKey(null, null); RequestMappingInfo none = new RequestMappingInfo(null, null);
request.addHeader("Accept", "application/xml, text/html"); request.addHeader("Accept", "application/xml, text/html");
Comparator<RequestMappingKey> comparator = handlerMapping.getMappingKeyComparator("", request); Comparator<RequestMappingInfo> comparator = handlerMapping.getMappingComparator("", 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);
@ -129,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.getMappingKeyComparator("", request); comparator = handlerMapping.getMappingComparator("", 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.getMappingKeyComparator("", request); comparator = handlerMapping.getMappingComparator("", 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);
@ -144,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.getMappingKeyComparator("", request); comparator = handlerMapping.getMappingComparator("", 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);

View File

@ -32,7 +32,7 @@ import org.springframework.web.servlet.mvc.method.condition.RequestConditionFact
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
/** /**
* Test fixture for {@link RequestMappingKey} tests. * Test fixture for {@link RequestMappingInfo} tests.
* *
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
@ -41,8 +41,8 @@ public class RequestKeyTests {
@Test @Test
public void equals() { public void equals() {
RequestMappingKey key1 = new RequestMappingKey(singleton("/foo"), singleton(GET)); RequestMappingInfo key1 = new RequestMappingInfo(singleton("/foo"), singleton(GET));
RequestMappingKey key2 = new RequestMappingKey(singleton("/foo"), singleton(GET)); RequestMappingInfo key2 = new RequestMappingInfo(singleton("/foo"), singleton(GET));
assertEquals(key1, key2); assertEquals(key1, key2);
assertEquals(key1.hashCode(), key2.hashCode()); assertEquals(key1.hashCode(), key2.hashCode());
@ -50,8 +50,8 @@ public class RequestKeyTests {
@Test @Test
public void equalsPrependSlash() { public void equalsPrependSlash() {
RequestMappingKey key1 = new RequestMappingKey(singleton("/foo"), singleton(GET)); RequestMappingInfo key1 = new RequestMappingInfo(singleton("/foo"), singleton(GET));
RequestMappingKey key2 = new RequestMappingKey(singleton("foo"), singleton(GET)); RequestMappingInfo key2 = new RequestMappingInfo(singleton("foo"), singleton(GET));
assertEquals(key1, key2); assertEquals(key1, key2);
assertEquals(key1.hashCode(), key2.hashCode()); assertEquals(key1.hashCode(), key2.hashCode());
@ -61,9 +61,9 @@ public class RequestKeyTests {
public void combinePatterns() { public void combinePatterns() {
AntPathMatcher pathMatcher = new AntPathMatcher(); AntPathMatcher pathMatcher = new AntPathMatcher();
RequestMappingKey key1 = createKeyFromPatterns("/t1", "/t2"); RequestMappingInfo key1 = createKeyFromPatterns("/t1", "/t2");
RequestMappingKey key2 = createKeyFromPatterns("/m1", "/m2"); RequestMappingInfo key2 = createKeyFromPatterns("/m1", "/m2");
RequestMappingKey key3 = createKeyFromPatterns("/t1/m1", "/t1/m2", "/t2/m1", "/t2/m2"); RequestMappingInfo 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");
@ -93,40 +93,40 @@ public class RequestKeyTests {
PathMatcher pathMatcher = new AntPathMatcher(); PathMatcher pathMatcher = new AntPathMatcher();
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null); RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null);
RequestMappingKey match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher); RequestMappingInfo match = key.getMatchingRequestMapping(pathHelper.getLookupPathForRequest(request), request, pathMatcher);
assertNotNull(match); assertNotNull(match);
request = new MockHttpServletRequest("GET", "/foo/bar"); request = new MockHttpServletRequest("GET", "/foo/bar");
key = new RequestMappingKey(singleton("/foo/*"), null); key = new RequestMappingInfo(singleton("/foo/*"), null);
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher); match = key.getMatchingRequestMapping(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 RequestMappingKey(singleton("/foo"), null); key = new RequestMappingInfo(singleton("/foo"), null);
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher); match = key.getMatchingRequestMapping(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 RequestMappingKey(singleton("/foo"), null); key = new RequestMappingInfo(singleton("/foo"), null);
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher); match = key.getMatchingRequestMapping(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 RequestMappingKey(singleton("/foo.jpg"), null); key = new RequestMappingInfo(singleton("/foo.jpg"), null);
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher); match = key.getMatchingRequestMapping(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 RequestMappingKey(singleton("/foo.jpg"), null); key = new RequestMappingInfo(singleton("/foo.jpg"), null);
match = key.getMatchingKey(pathHelper.getLookupPathForRequest(request), request, pathMatcher); match = key.getMatchingRequestMapping(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);
} }
@ -137,18 +137,18 @@ public class RequestKeyTests {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null); RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null);
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher); RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
assertNotNull("No method matches any method", match); assertNotNull("No method matches any method", match);
key = new RequestMappingKey(singleton("/foo"), singleton(GET)); key = new RequestMappingInfo(singleton("/foo"), singleton(GET));
match = key.getMatchingKey(lookupPath, request, pathMatcher); match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
assertNotNull("Exact match", match); assertNotNull("Exact match", match);
key = new RequestMappingKey(singleton("/foo"), singleton(POST)); key = new RequestMappingInfo(singleton("/foo"), singleton(POST));
match = key.getMatchingKey(lookupPath, request, pathMatcher); match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
assertNull("No match", match); assertNull("No match", match);
} }
@ -159,15 +159,15 @@ public class RequestKeyTests {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo"); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
RequestMappingKey key = new RequestMappingKey(asList("/foo*", "/bar"), asList(GET, POST)); RequestMappingInfo key = new RequestMappingInfo(asList("/foo*", "/bar"), asList(GET, POST));
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher); RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
RequestMappingKey expected = new RequestMappingKey(singleton("/foo*"), singleton(GET)); RequestMappingInfo expected = new RequestMappingInfo(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 RequestMappingKey(asList("/**", "/foo*", "/foo"), null); key = new RequestMappingInfo(asList("/**", "/foo*", "/foo"), null);
match = key.getMatchingKey(lookupPath, request, pathMatcher); match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
expected = new RequestMappingKey(asList("/foo", "/foo*", "/**"), null); expected = new RequestMappingInfo(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);
} }
@ -179,13 +179,13 @@ public class RequestKeyTests {
request.setParameter("foo", "bar"); request.setParameter("foo", "bar");
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
RequestMappingKey key = new RequestMappingKey(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null, null); RequestMappingInfo key = new RequestMappingInfo(asList("/foo"), null, RequestConditionFactory.parseParams("foo=bar"), null);
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher); RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
assertNotNull(match); assertNotNull(match);
key = new RequestMappingKey(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null, null); key = new RequestMappingInfo(singleton("/foo"), null, RequestConditionFactory.parseParams("foo!=bar"), null);
match = key.getMatchingKey(lookupPath, request, pathMatcher); match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
assertNull(match); assertNull(match);
} }
@ -197,39 +197,39 @@ public class RequestKeyTests {
request.addHeader("foo", "bar"); request.addHeader("foo", "bar");
String lookupPath = new UrlPathHelper().getLookupPathForRequest(request); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"), null); RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo=bar"));
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher); RequestMappingInfo match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
assertNotNull(match); assertNotNull(match);
key = new RequestMappingKey(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"), null); key = new RequestMappingInfo(singleton("/foo"), null, null, RequestConditionFactory.parseHeaders("foo!=bar"));
match = key.getMatchingKey(lookupPath, request, pathMatcher); match = key.getMatchingRequestMapping(lookupPath, request, pathMatcher);
assertNull(match); assertNull(match);
} }
@Test // @Test
public void consumesCondition() { // public void consumesCondition() {
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); // String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);
//
// RequestMappingInfo key = new RequestMappingInfo(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
// "text/plain"));
// RequestMappingInfo match = key.getMatchingKey(lookupPath, request, pathMatcher);
//
// assertNotNull(match);
//
// key = new RequestMappingInfo(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
// "application/xml"));
// match = key.getMatchingKey(lookupPath, request, pathMatcher);
//
// assertNull(match);
// }
RequestMappingKey key = new RequestMappingKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes( private RequestMappingInfo createKeyFromPatterns(String... patterns) {
"text/plain")); return new RequestMappingInfo(asList(patterns), null);
RequestMappingKey match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNotNull(match);
key = new RequestMappingKey(singleton("/foo"), null, null, null, RequestConditionFactory.parseConsumes(
"application/xml"));
match = key.getMatchingKey(lookupPath, request, pathMatcher);
assertNull(match);
}
private RequestMappingKey createKeyFromPatterns(String... patterns) {
return new RequestMappingKey(asList(patterns), null);
} }
} }

View File

@ -124,7 +124,7 @@ public class RequestMappingHandlerMethodMappingTests {
@Test @Test
public void uriTemplateVariables() { public void uriTemplateVariables() {
RequestMappingKey key = new RequestMappingKey(Arrays.asList("/{path1}/{path2}"), null); RequestMappingInfo key = new RequestMappingInfo(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); String lookupPath = new UrlPathHelper().getLookupPathForRequest(request);