SPR-8247 review changes
This commit is contained in:
@@ -41,7 +41,7 @@ import org.springframework.web.util.UrlPathHelper;
|
||||
* Abstract base class for {@link org.springframework.web.servlet.HandlerMapping HandlerMapping} implementations that
|
||||
* support mapping requests to {@link HandlerMethod}s rather than to handlers.
|
||||
*
|
||||
* @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 Rossen Stoyanchev
|
||||
@@ -106,7 +106,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
protected void initHandlerMethods() {
|
||||
@@ -135,57 +135,57 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
|
||||
Set<Method> methods = HandlerMethodSelector.selectMethods(handlerType, new MethodFilter() {
|
||||
public boolean matches(Method method) {
|
||||
return getMappingKeyForMethod(beanName, method) != null;
|
||||
return getMappingForMethod(beanName, method) != null;
|
||||
}
|
||||
});
|
||||
for (Method method : methods) {
|
||||
HandlerMethod handlerMethod = new HandlerMethod(beanName, getApplicationContext(), method);
|
||||
T mapping = getMappingKeyForMethod(beanName, method);
|
||||
T mapping = getMappingForMethod(beanName, method);
|
||||
Set<String> paths = getMappingPaths(mapping);
|
||||
registerHandlerMethod(paths, mapping, handlerMethod);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a mapping key for the given bean method. A method for which no mapping can be determined is
|
||||
* not considered a handler method.
|
||||
* Provides a request mapping for the given bean method. A method for which no request mapping can be determined
|
||||
* is not considered a handler method.
|
||||
*
|
||||
* @param beanName the name of the bean the method belongs to
|
||||
* @param method the method to create a 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.
|
||||
*
|
||||
* @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
|
||||
* @throws IllegalStateException if another method was already register under the same mapping
|
||||
*/
|
||||
protected void registerHandlerMethod(Set<String> paths, T mappingKey, HandlerMethod handlerMethod) {
|
||||
Assert.notNull(mappingKey, "'mapping' must not be null");
|
||||
protected void registerHandlerMethod(Set<String> paths, T mapping, HandlerMethod handlerMethod) {
|
||||
Assert.notNull(mapping, "'mapping' 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)) {
|
||||
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.");
|
||||
}
|
||||
handlerMethods.put(mappingKey, handlerMethod);
|
||||
handlerMethods.put(mapping, handlerMethod);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Mapped \"" + mappingKey + "\" onto " + handlerMethod);
|
||||
logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);
|
||||
}
|
||||
for (String path : paths) {
|
||||
urlMap.add(path, mappingKey);
|
||||
urlMap.add(path, mapping);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL paths for the given mapping.
|
||||
*/
|
||||
protected abstract Set<String> getMappingPaths(T mappingKey);
|
||||
protected abstract Set<String> getMappingPaths(T mapping);
|
||||
|
||||
@Override
|
||||
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.
|
||||
*
|
||||
* <p>This implementation iterators through all handler methods, calls {@link #getMatchingKey(Object,
|
||||
* HttpServletRequest)} for each of them, {@linkplain #getKeyComparator(HttpServletRequest) sorts} all matches, and
|
||||
* returns the 1st entry, if any. If no matches are found, {@link #handleNoMatch(Set, HttpServletRequest)} is
|
||||
* invoked.
|
||||
* <p>This implementation iterators through all handler methods, calls
|
||||
* {@link #getMatchingMapping(Object, String, HttpServletRequest)} for each of them,
|
||||
* sorts all matches via {@linkplain #getMappingComparator(String, HttpServletRequest)} , and returns the
|
||||
* 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 request the current HTTP servlet request
|
||||
* @return the best-matching handler method, or {@code null} if there is no match
|
||||
*/
|
||||
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
|
||||
List<T> keys = urlMap.get(lookupPath);
|
||||
if (keys == null) {
|
||||
keys = new ArrayList<T>(handlerMethods.keySet());
|
||||
List<T> mappings = urlMap.get(lookupPath);
|
||||
if (mappings == null) {
|
||||
mappings = new ArrayList<T>(handlerMethods.keySet());
|
||||
}
|
||||
|
||||
List<Match> matches = new ArrayList<Match>();
|
||||
|
||||
for (T key : keys) {
|
||||
T match = getMatchingMappingKey(key, lookupPath, request);
|
||||
for (T mapping : mappings) {
|
||||
T match = getMatchingMapping(mapping, lookupPath, request);
|
||||
if (match != null) {
|
||||
matches.add(new Match(match, handlerMethods.get(key)));
|
||||
matches.add(new Match(match, handlerMethods.get(mapping)));
|
||||
}
|
||||
}
|
||||
|
||||
if (!matches.isEmpty()) {
|
||||
Comparator<Match> comparator = new MatchComparator(getMappingKeyComparator(lookupPath, request));
|
||||
Comparator<Match> comparator = new MatchComparator(getMappingComparator(lookupPath, request));
|
||||
Collections.sort(matches, comparator);
|
||||
|
||||
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;
|
||||
}
|
||||
else {
|
||||
@@ -266,12 +266,12 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
/**
|
||||
* Invoked when a request has been matched to a mapping.
|
||||
*
|
||||
* @param mappingKey the mapping selected for the request returned by
|
||||
* {@link #getMatchingMappingKey(Object, String, HttpServletRequest)}.
|
||||
* @param mapping the mapping selected for the request returned by
|
||||
* {@link #getMatchingMapping(Object, String, HttpServletRequest)}.
|
||||
* @param lookupPath mapping lookup path within the current servlet mapping if applicable
|
||||
* @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
|
||||
* 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 request the current HTTP servlet 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 request the current HTTP servlet request
|
||||
* @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}.
|
||||
*
|
||||
* @param mappingKeys all registered mappings
|
||||
* @param mappings all registered request mappings
|
||||
* @param lookupPath mapping lookup path within the current servlet mapping if applicable
|
||||
* @param request the current HTTP request
|
||||
* @throws ServletException in case of errors
|
||||
*/
|
||||
protected HandlerMethod handleNoMatch(Set<T> mappingKeys, String lookupPath, HttpServletRequest request)
|
||||
protected HandlerMethod handleNoMatch(Set<T> mappings, String lookupPath, HttpServletRequest request)
|
||||
throws Exception {
|
||||
return null;
|
||||
}
|
||||
|
||||
private class Match {
|
||||
|
||||
private final T mappingKey;
|
||||
private final T mapping;
|
||||
|
||||
private final HandlerMethod handlerMethod;
|
||||
|
||||
private Match(T mapping, HandlerMethod handlerMethod) {
|
||||
this.mappingKey = mapping;
|
||||
this.mapping = mapping;
|
||||
this.handlerMethod = handlerMethod;
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
return comparator.compare(match1.mappingKey, match2.mappingKey);
|
||||
return comparator.compare(match1.mapping, match2.mapping);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,14 +46,14 @@ import org.springframework.web.servlet.handler.MappedInterceptors;
|
||||
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.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMapping<RequestMappingKey> {
|
||||
public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
|
||||
|
||||
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.
|
||||
* Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
|
||||
* attributes combined with method-level {@link RequestMapping @RequestMapping} attributes.
|
||||
*
|
||||
* @param beanName the name of the bean the method belongs to
|
||||
* @param method the method to create a key for
|
||||
* @return the key, or {@code null}
|
||||
* @see RequestMappingKey#combine(RequestMappingKey, PathMatcher)
|
||||
* @param method the method to create a mapping for
|
||||
* @return the mapping, or {@code null}
|
||||
* @see RequestMappingInfo#combine(RequestMappingInfo, PathMatcher)
|
||||
*/
|
||||
@Override
|
||||
protected RequestMappingKey getMappingKeyForMethod(String beanName, Method method) {
|
||||
protected RequestMappingInfo getMappingForMethod(String beanName, Method method) {
|
||||
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||
if (annotation != null) {
|
||||
RequestMappingKey methodKey = createFromRequestMapping(annotation);
|
||||
RequestMappingInfo methodMapping = createFromRequestMapping(annotation);
|
||||
RequestMapping typeAnnot = getApplicationContext().findAnnotationOnBean(beanName, RequestMapping.class);
|
||||
if (typeAnnot != null) {
|
||||
RequestMappingKey typeKey = createFromRequestMapping(typeAnnot);
|
||||
return typeKey.combine(methodKey, pathMatcher);
|
||||
RequestMappingInfo typeMapping = createFromRequestMapping(typeAnnot);
|
||||
return typeMapping.combine(methodMapping, pathMatcher);
|
||||
}
|
||||
else {
|
||||
return methodKey;
|
||||
return methodMapping;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -126,55 +126,53 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
|
||||
}
|
||||
}
|
||||
|
||||
private static RequestMappingKey createFromRequestMapping(RequestMapping annotation) {
|
||||
return new RequestMappingKey(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()),
|
||||
private static RequestMappingInfo createFromRequestMapping(RequestMapping annotation) {
|
||||
return new RequestMappingInfo(Arrays.asList(annotation.value()), Arrays.asList(annotation.method()),
|
||||
RequestConditionFactory.parseParams(annotation.params()),
|
||||
RequestConditionFactory.parseHeaders(annotation.headers()),
|
||||
RequestConditionFactory.parseConsumes(annotation.consumes())
|
||||
);
|
||||
RequestConditionFactory.parseHeaders(annotation.headers()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Set<String> getMappingPaths(RequestMappingKey key) {
|
||||
return key.getPatterns();
|
||||
protected Set<String> getMappingPaths(RequestMappingInfo mapping) {
|
||||
return mapping.getPatterns();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link RequestMappingKey} with attributes matching to the current request or {@code null}.
|
||||
* @see RequestMappingKey#getMatchingKey(String, HttpServletRequest, PathMatcher)
|
||||
* Returns a new {@link RequestMappingInfo} with attributes matching to the current request or {@code null}.
|
||||
* @see RequestMappingInfo#getMatchingRequestMapping(String, HttpServletRequest, PathMatcher)
|
||||
*/
|
||||
@Override
|
||||
protected RequestMappingKey getMatchingMappingKey(RequestMappingKey key, String lookupPath, HttpServletRequest request) {
|
||||
return key.getMatchingKey(lookupPath, request, pathMatcher);
|
||||
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping, String lookupPath, HttpServletRequest request) {
|
||||
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
|
||||
protected Comparator<RequestMappingKey> getMappingKeyComparator(String lookupPath, HttpServletRequest request) {
|
||||
return new RequestKeyComparator(lookupPath, request);
|
||||
protected Comparator<RequestMappingInfo> getMappingComparator(String lookupPath, HttpServletRequest request) {
|
||||
return new RequestMappingInfoComparator(lookupPath, request);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleMatch(RequestMappingKey key, String lookupPath, HttpServletRequest request) {
|
||||
String pattern = key.getPatterns().iterator().next();
|
||||
protected void handleMatch(RequestMappingInfo mapping, String lookupPath, HttpServletRequest request) {
|
||||
String pattern = mapping.getPatterns().iterator().next();
|
||||
Map<String, String> uriTemplateVariables = pathMatcher.extractUriTemplateVariables(pattern, lookupPath);
|
||||
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
|
||||
*/
|
||||
@Override
|
||||
protected HandlerMethod handleNoMatch(Set<RequestMappingKey> requestKeys, String lookupPath, HttpServletRequest request)
|
||||
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos, String lookupPath, HttpServletRequest request)
|
||||
throws HttpRequestMethodNotSupportedException {
|
||||
Set<String> allowedMethods = new HashSet<String>(6);
|
||||
for (RequestMappingKey requestKey : requestKeys) {
|
||||
for (String pattern : requestKey.getPatterns()) {
|
||||
for (RequestMappingInfo info : requestMappingInfos) {
|
||||
for (String pattern : info.getPatterns()) {
|
||||
if (pathMatcher.match(pattern, lookupPath)) {
|
||||
for (RequestMethod method : requestKey.getMethods()) {
|
||||
for (RequestMethod method : info.getMethods()) {
|
||||
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
|
||||
* specific request. For example not all {@link RequestMappingKey} patterns may apply to the current request.
|
||||
* A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context of a
|
||||
* specific request. For example not all {@link RequestMappingInfo} patterns may apply to the current request.
|
||||
* Therefore an HttpServletRequest is required as input.
|
||||
*
|
||||
* <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
|
||||
* patterns only <li>Patterns are ordered with the best matching pattern at the top </ul>
|
||||
* <p>Furthermore, the following assumptions are made about the input RequestMappings:
|
||||
* <ul><li>Each RequestMappingInfo has been fully matched to the request <li>The RequestMappingInfo contains
|
||||
* 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 List<MediaType> requestAcceptHeader;
|
||||
|
||||
public RequestKeyComparator(String lookupPath, HttpServletRequest request) {
|
||||
public RequestMappingInfoComparator(String lookupPath, HttpServletRequest request) {
|
||||
this.patternComparator = pathMatcher.getPatternComparator(lookupPath);
|
||||
String acceptHeader = request.getHeader("Accept");
|
||||
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
|
||||
MediaType.sortByQualityValue(this.requestAcceptHeader);
|
||||
}
|
||||
|
||||
public int compare(RequestMappingKey key, RequestMappingKey otherKey) {
|
||||
int result = comparePatterns(key.getPatterns(), otherKey.getPatterns());
|
||||
public int compare(RequestMappingInfo mapping, RequestMappingInfo otherMapping) {
|
||||
int result = comparePatterns(mapping.getPatterns(), otherMapping.getPatterns());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = key.getParams().compareTo(otherKey.getParams());
|
||||
result = mapping.getParams().compareTo(otherMapping.getParams());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
result = key.getHeaders().compareTo(otherKey.getHeaders());
|
||||
result = mapping.getHeaders().compareTo(otherMapping.getHeaders());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
/*
|
||||
TODO: fix
|
||||
result = compareAcceptHeaders(key.getAcceptHeaderMediaTypes(), otherKey.getAcceptHeaderMediaTypes());
|
||||
result = compareAcceptHeaders(mapping.getAcceptHeaderMediaTypes(), otherMapping.getAcceptHeaderMediaTypes());
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
result = otherKey.getMethods().size() - key.getMethods().size();
|
||||
result = otherMapping.getMethods().size() - mapping.getMethods().size();
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -32,20 +32,18 @@ import org.springframework.web.servlet.mvc.method.condition.RequestCondition;
|
||||
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
|
||||
* parameters and headers.
|
||||
* Contains a set of conditions to match to a given request such as URL patterns, HTTP methods, request parameters
|
||||
* and headers.
|
||||
*
|
||||
* <p>A {@link RequestMappingKey} can be combined with another {@link RequestMappingKey} resulting in a new {@link RequestMappingKey}
|
||||
* with conditions from both (see {@link #combine(RequestMappingKey, PathMatcher)}).
|
||||
*
|
||||
* <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)}).
|
||||
* <p>Two {@link RequestMappingInfo}s can be combined resulting in a new {@link RequestMappingInfo} with conditions
|
||||
* 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.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public final class RequestMappingKey {
|
||||
public final class RequestMappingInfo {
|
||||
|
||||
private final Set<String> patterns;
|
||||
|
||||
@@ -55,8 +53,6 @@ public final class RequestMappingKey {
|
||||
|
||||
private final RequestCondition headersCondition;
|
||||
|
||||
private final RequestCondition consumesCondition;
|
||||
|
||||
private int hash;
|
||||
|
||||
/**
|
||||
@@ -64,23 +60,21 @@ public final class RequestMappingKey {
|
||||
*
|
||||
* <p>Package protected for testing purposes.
|
||||
*/
|
||||
RequestMappingKey(Collection<String> patterns, Collection<RequestMethod> methods) {
|
||||
this(patterns, methods, null, null, null);
|
||||
RequestMappingInfo(Collection<String> patterns, Collection<RequestMethod> methods) {
|
||||
this(patterns, methods, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
RequestCondition paramsCondition,
|
||||
RequestCondition headersCondition,
|
||||
RequestCondition consumesCondition) {
|
||||
RequestCondition headersCondition) {
|
||||
this.patterns = asUnmodifiableSet(prependLeadingSlash(patterns));
|
||||
this.methods = asUnmodifiableSet(methods);
|
||||
this.paramsCondition = paramsCondition != null ? paramsCondition : RequestConditionFactory.trueCondition();
|
||||
this.headersCondition = headersCondition != null ? headersCondition : RequestConditionFactory.trueCondition();
|
||||
this.consumesCondition = consumesCondition != null ? consumesCondition : RequestConditionFactory.trueCondition();
|
||||
}
|
||||
|
||||
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>Request parameter are combined into a logical AND.
|
||||
* <li>Request header are combined into a logical AND.
|
||||
* <li>Consumes .. TODO
|
||||
* </ul>
|
||||
* @param methodKey the key to combine with
|
||||
* @param pathMatcher to {@linkplain PathMatcher#combine(String, String) combine} the patterns
|
||||
* @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<RequestMethod> methods = union(this.methods, methodKey.methods);
|
||||
RequestCondition params = RequestConditionFactory.and(this.paramsCondition, methodKey.paramsCondition);
|
||||
RequestCondition headers = RequestConditionFactory.and(this.headersCondition, methodKey.headersCondition);
|
||||
RequestCondition consumes = RequestConditionFactory.mostSpecific(methodKey.consumesCondition, this.consumesCondition);
|
||||
|
||||
return new RequestMappingKey(patterns, methods, params, headers, consumes);
|
||||
return new RequestMappingInfo(patterns, methods, params, headers);
|
||||
}
|
||||
|
||||
private static Set<String> combinePatterns(Collection<String> typePatterns,
|
||||
@@ -204,17 +196,15 @@ public final class RequestMappingKey {
|
||||
* @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
|
||||
*/
|
||||
public RequestMappingKey getMatchingKey(String lookupPath, HttpServletRequest request, PathMatcher pathMatcher) {
|
||||
if (!checkMethod(request) || !paramsCondition.match(request) || !headersCondition.match(request) ||
|
||||
!consumesCondition.match(request)) {
|
||||
public RequestMappingInfo getMatchingRequestMapping(String lookupPath, HttpServletRequest request, PathMatcher pathMatcher) {
|
||||
if (!checkMethod(request) || !paramsCondition.match(request) || !headersCondition.match(request)) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
List<String> matchingPatterns = getMatchingPatterns(lookupPath, request, pathMatcher);
|
||||
if (!matchingPatterns.isEmpty()) {
|
||||
Set<RequestMethod> matchingMethods = getMatchingMethod(request);
|
||||
return new RequestMappingKey(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition,
|
||||
this.consumesCondition);
|
||||
return new RequestMappingInfo(matchingPatterns, matchingMethods, this.paramsCondition, this.headersCondition);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
@@ -275,8 +265,8 @@ public final class RequestMappingKey {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj != null && obj instanceof RequestMappingKey) {
|
||||
RequestMappingKey other = (RequestMappingKey) obj;
|
||||
if (obj != null && obj instanceof RequestMappingInfo) {
|
||||
RequestMappingInfo other = (RequestMappingInfo) obj;
|
||||
return (this.patterns.equals(other.patterns) && this.methods.equals(other.methods) &&
|
||||
this.paramsCondition.equals(other.paramsCondition) &&
|
||||
this.headersCondition.equals(other.headersCondition));
|
||||
@@ -307,7 +297,6 @@ public final class RequestMappingKey {
|
||||
}
|
||||
builder.append(",params=").append(paramsCondition.toString());
|
||||
builder.append(",headers=").append(headersCondition.toString());
|
||||
builder.append(",consumes=").append(consumesCondition.toString());
|
||||
builder.append('}');
|
||||
return builder.toString();
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
/**
|
||||
* Defines the contract for conditions that must be met before an incoming request matches a {@link
|
||||
* org.springframework.web.servlet.mvc.method.annotation.RequestMappingKey RequestKey}.
|
||||
* org.springframework.web.servlet.mvc.method.annotation.RequestMappingInfo RequestKey}.
|
||||
*
|
||||
* <p>Implementations of this interface are created by the {@link RequestConditionFactory}.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user