Extract base class from RequestMappingHandlerMapping, one that allows for discovering request mappings from something other than annotations
This commit is contained in:
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.web.servlet.mvc.method.annotation;
|
package org.springframework.web.servlet.mvc.method;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -0,0 +1,228 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2002-2011 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.web.servlet.mvc.method;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.util.PathMatcher;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||||
|
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||||
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingInfo} to represent request
|
||||||
|
* mapping conditions.
|
||||||
|
*
|
||||||
|
* @author Arjen Poutsma
|
||||||
|
* @author Rossen Stoyanchev
|
||||||
|
* @since 3.1.0
|
||||||
|
*/
|
||||||
|
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void handlerMethodsInitialized(Map<RequestMappingInfo, HandlerMethod> handlerMethods) {
|
||||||
|
List<RequestMappingInfo> mappings = new ArrayList<RequestMappingInfo>(handlerMethods.keySet());
|
||||||
|
while (mappings.size() > 1) {
|
||||||
|
RequestMappingInfo mapping = mappings.remove(0);
|
||||||
|
for (RequestMappingInfo otherMapping : mappings) {
|
||||||
|
// further validate mapping conditions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Set<String> getMappingPaths(RequestMappingInfo mapping) {
|
||||||
|
return mapping.getPatterns();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a new {@link RequestMappingInfo} with attributes matching to the current request or {@code null}.
|
||||||
|
*
|
||||||
|
* @see RequestMappingInfo#getMatchingRequestMapping(String, HttpServletRequest, PathMatcher)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping,
|
||||||
|
String lookupPath,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
return mapping.getMatchingRequestMapping(lookupPath, request, getPathMatcher());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestMappingInfo}.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Comparator<RequestMappingInfo> getMappingComparator(String lookupPath, HttpServletRequest request) {
|
||||||
|
return new RequestMappingInfoComparator(lookupPath, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exposes URI template variables and producible media types as request attributes.
|
||||||
|
*
|
||||||
|
* @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE
|
||||||
|
* @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
|
||||||
|
super.handleMatch(info, lookupPath, request);
|
||||||
|
|
||||||
|
String pattern = info.getPatterns().iterator().next();
|
||||||
|
Map<String, String> uriTemplateVariables = getPathMatcher().extractUriTemplateVariables(pattern, lookupPath);
|
||||||
|
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
|
||||||
|
|
||||||
|
if (!info.getProduces().isEmpty()) {
|
||||||
|
Set<MediaType> mediaTypes = info.getProduces().getMediaTypes();
|
||||||
|
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterates all {@link RequestMappingInfo}s looking for mappings that match by URL but not by HTTP method.
|
||||||
|
*
|
||||||
|
* @throws HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
|
||||||
|
String lookupPath,
|
||||||
|
HttpServletRequest request) throws ServletException {
|
||||||
|
Set<String> allowedMethods = new HashSet<String>(6);
|
||||||
|
Set<MediaType> consumableMediaTypes = new HashSet<MediaType>();
|
||||||
|
Set<MediaType> producibleMediaTypes = new HashSet<MediaType>();
|
||||||
|
for (RequestMappingInfo info : requestMappingInfos) {
|
||||||
|
for (String pattern : info.getPatterns()) {
|
||||||
|
if (getPathMatcher().match(pattern, lookupPath)) {
|
||||||
|
if (!info.getMethods().match(request)) {
|
||||||
|
for (RequestMethod method : info.getMethods().getMethods()) {
|
||||||
|
allowedMethods.add(method.name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!info.getConsumes().match(request)) {
|
||||||
|
consumableMediaTypes.addAll(info.getConsumes().getMediaTypes());
|
||||||
|
}
|
||||||
|
if (!info.getProduces().match(request)) {
|
||||||
|
producibleMediaTypes.addAll(info.getProduces().getMediaTypes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!allowedMethods.isEmpty()) {
|
||||||
|
throw new HttpRequestMethodNotSupportedException(request.getMethod(), allowedMethods);
|
||||||
|
}
|
||||||
|
else if (!consumableMediaTypes.isEmpty()) {
|
||||||
|
MediaType contentType = null;
|
||||||
|
if (StringUtils.hasLength(request.getContentType())) {
|
||||||
|
contentType = MediaType.parseMediaType(request.getContentType());
|
||||||
|
}
|
||||||
|
throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<MediaType>(consumableMediaTypes));
|
||||||
|
}
|
||||||
|
else if (!producibleMediaTypes.isEmpty()) {
|
||||||
|
throw new HttpMediaTypeNotAcceptableException(new ArrayList<MediaType>(producibleMediaTypes));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 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 RequestMappingInfoHandlerMapping#getMatchingMapping(RequestMappingInfo, String, HttpServletRequest)
|
||||||
|
*/
|
||||||
|
private class RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {
|
||||||
|
|
||||||
|
private Comparator<String> patternComparator;
|
||||||
|
|
||||||
|
private List<MediaType> requestAcceptHeader;
|
||||||
|
|
||||||
|
public RequestMappingInfoComparator(String lookupPath, HttpServletRequest request) {
|
||||||
|
this.patternComparator = getPathMatcher().getPatternComparator(lookupPath);
|
||||||
|
String acceptHeader = request.getHeader("Accept");
|
||||||
|
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
|
||||||
|
MediaType.sortByQualityValue(this.requestAcceptHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int compare(RequestMappingInfo mapping, RequestMappingInfo otherMapping) {
|
||||||
|
int result = comparePatterns(mapping.getPatterns(), otherMapping.getPatterns());
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = mapping.getParams().compareTo(otherMapping.getParams());
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = mapping.getHeaders().compareTo(otherMapping.getHeaders());
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = mapping.getConsumes().compareTo(otherMapping.getConsumes());
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = mapping.getProduces().compareTo(otherMapping.getProduces(), this.requestAcceptHeader);
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result = mapping.getMethods().compareTo(otherMapping.getMethods());
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int comparePatterns(Set<String> patterns, Set<String> otherPatterns) {
|
||||||
|
Iterator<String> iterator = patterns.iterator();
|
||||||
|
Iterator<String> iteratorOther = otherPatterns.iterator();
|
||||||
|
while (iterator.hasNext() && iteratorOther.hasNext()) {
|
||||||
|
int result = patternComparator.compare(iterator.next(), iteratorOther.next());
|
||||||
|
if (result != 0) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else if (iteratorOther.hasNext()) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,42 +17,25 @@
|
|||||||
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.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.PathMatcher;
|
import org.springframework.util.PathMatcher;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
|
||||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
|
||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
|
||||||
import org.springframework.web.servlet.HandlerMapping;
|
|
||||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
|
||||||
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 RequestMappingInfo}s for the registration and the
|
* A sub-class of {@link RequestMappingInfoHandlerMapping} that prepares {@link RequestMappingInfo}s
|
||||||
* lookup of {@link HandlerMethod}s.
|
* from @{@link RequestMapping} annotations on @{@link Controller} classes.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 3.1.0
|
* @since 3.1.0
|
||||||
*/
|
*/
|
||||||
public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
|
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@inheritDoc} The handler determination in this method is made based on the presence of a type-level {@link
|
* {@inheritDoc} The handler determination in this method is made based on the presence of a type-level {@link
|
||||||
@@ -63,17 +46,6 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
|
|||||||
return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
|
return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void handlerMethodsInitialized(Map<RequestMappingInfo, HandlerMethod> handlerMethods) {
|
|
||||||
List<RequestMappingInfo> mappings = new ArrayList<RequestMappingInfo>(handlerMethods.keySet());
|
|
||||||
while (mappings.size() > 1) {
|
|
||||||
RequestMappingInfo mapping = mappings.remove(0);
|
|
||||||
for (RequestMappingInfo otherMapping : mappings) {
|
|
||||||
// further validate mapping conditions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a {@link RequestMappingInfo} for the given method. <p>Only {@link RequestMapping @RequestMapping}-annotated
|
* 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
|
* methods are considered. Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
|
||||||
@@ -112,170 +84,4 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
|
|||||||
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers()));
|
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Set<String> getMappingPaths(RequestMappingInfo mapping) {
|
|
||||||
return mapping.getPatterns();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a new {@link RequestMappingInfo} with attributes matching to the current request or {@code null}.
|
|
||||||
*
|
|
||||||
* @see RequestMappingInfo#getMatchingRequestMapping(String, HttpServletRequest, PathMatcher)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping,
|
|
||||||
String lookupPath,
|
|
||||||
HttpServletRequest request) {
|
|
||||||
return mapping.getMatchingRequestMapping(lookupPath, request, getPathMatcher());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a {@link Comparator} that can be used to sort and select the best matching {@link RequestMappingInfo}.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Comparator<RequestMappingInfo> getMappingComparator(String lookupPath, HttpServletRequest request) {
|
|
||||||
return new RequestMappingInfoComparator(lookupPath, request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exposes URI template variables and producible media types as request attributes.
|
|
||||||
*
|
|
||||||
* @see HandlerMapping#URI_TEMPLATE_VARIABLES_ATTRIBUTE
|
|
||||||
* @see HandlerMapping#PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
|
|
||||||
super.handleMatch(info, lookupPath, request);
|
|
||||||
|
|
||||||
String pattern = info.getPatterns().iterator().next();
|
|
||||||
Map<String, String> uriTemplateVariables = getPathMatcher().extractUriTemplateVariables(pattern, lookupPath);
|
|
||||||
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
|
|
||||||
|
|
||||||
if (!info.getProduces().isEmpty()) {
|
|
||||||
Set<MediaType> mediaTypes = info.getProduces().getMediaTypes();
|
|
||||||
request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates all {@link RequestMappingInfo}s looking for mappings that match by URL but not by HTTP method.
|
|
||||||
*
|
|
||||||
* @throws HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
|
|
||||||
String lookupPath,
|
|
||||||
HttpServletRequest request) throws ServletException {
|
|
||||||
Set<String> allowedMethods = new HashSet<String>(6);
|
|
||||||
Set<MediaType> consumableMediaTypes = new HashSet<MediaType>();
|
|
||||||
Set<MediaType> producibleMediaTypes = new HashSet<MediaType>();
|
|
||||||
for (RequestMappingInfo info : requestMappingInfos) {
|
|
||||||
for (String pattern : info.getPatterns()) {
|
|
||||||
if (getPathMatcher().match(pattern, lookupPath)) {
|
|
||||||
if (!info.getMethods().match(request)) {
|
|
||||||
for (RequestMethod method : info.getMethods().getMethods()) {
|
|
||||||
allowedMethods.add(method.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!info.getConsumes().match(request)) {
|
|
||||||
consumableMediaTypes.addAll(info.getConsumes().getMediaTypes());
|
|
||||||
}
|
|
||||||
if (!info.getProduces().match(request)) {
|
|
||||||
producibleMediaTypes.addAll(info.getProduces().getMediaTypes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!allowedMethods.isEmpty()) {
|
|
||||||
throw new HttpRequestMethodNotSupportedException(request.getMethod(), allowedMethods);
|
|
||||||
}
|
|
||||||
else if (!consumableMediaTypes.isEmpty()) {
|
|
||||||
MediaType contentType = null;
|
|
||||||
if (StringUtils.hasLength(request.getContentType())) {
|
|
||||||
contentType = MediaType.parseMediaType(request.getContentType());
|
|
||||||
}
|
|
||||||
throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<MediaType>(consumableMediaTypes));
|
|
||||||
}
|
|
||||||
else if (!producibleMediaTypes.isEmpty()) {
|
|
||||||
throw new HttpMediaTypeNotAcceptableException(new ArrayList<MediaType>(producibleMediaTypes));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 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 RequestMappingHandlerMapping#getMatchingMapping(RequestMappingInfo, String, HttpServletRequest)
|
|
||||||
*/
|
|
||||||
private class RequestMappingInfoComparator implements Comparator<RequestMappingInfo> {
|
|
||||||
|
|
||||||
private Comparator<String> patternComparator;
|
|
||||||
|
|
||||||
private List<MediaType> requestAcceptHeader;
|
|
||||||
|
|
||||||
public RequestMappingInfoComparator(String lookupPath, HttpServletRequest request) {
|
|
||||||
this.patternComparator = getPathMatcher().getPatternComparator(lookupPath);
|
|
||||||
String acceptHeader = request.getHeader("Accept");
|
|
||||||
this.requestAcceptHeader = MediaType.parseMediaTypes(acceptHeader);
|
|
||||||
MediaType.sortByQualityValue(this.requestAcceptHeader);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int compare(RequestMappingInfo mapping, RequestMappingInfo otherMapping) {
|
|
||||||
int result = comparePatterns(mapping.getPatterns(), otherMapping.getPatterns());
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = mapping.getParams().compareTo(otherMapping.getParams());
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = mapping.getHeaders().compareTo(otherMapping.getHeaders());
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = mapping.getConsumes().compareTo(otherMapping.getConsumes());
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = mapping.getProduces().compareTo(otherMapping.getProduces(), this.requestAcceptHeader);
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = mapping.getMethods().compareTo(otherMapping.getMethods());
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int comparePatterns(Set<String> patterns, Set<String> otherPatterns) {
|
|
||||||
Iterator<String> iterator = patterns.iterator();
|
|
||||||
Iterator<String> iteratorOther = otherPatterns.iterator();
|
|
||||||
while (iterator.hasNext() && iteratorOther.hasNext()) {
|
|
||||||
int result = patternComparator.compare(iterator.next(), iteratorOther.next());
|
|
||||||
if (result != 0) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (iterator.hasNext()) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
else if (iteratorOther.hasNext()) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ package org.springframework.web.servlet.mvc.method.condition;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
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 given an incoming request.
|
||||||
* 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}.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -14,8 +14,9 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.web.servlet.mvc.method.annotation;
|
package org.springframework.web.servlet.mvc.method;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -25,6 +26,8 @@ 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.RequestMappingInfo;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
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;
|
||||||
|
|
||||||
@@ -39,13 +42,13 @@ import static org.junit.Assert.*;
|
|||||||
*/
|
*/
|
||||||
public class RequestMappingInfoComparatorTests {
|
public class RequestMappingInfoComparatorTests {
|
||||||
|
|
||||||
private RequestMappingHandlerMapping handlerMapping;
|
private TestRequestMappingInfoHandlerMapping handlerMapping;
|
||||||
|
|
||||||
private MockHttpServletRequest request;
|
private MockHttpServletRequest request;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setup() {
|
public void setup() {
|
||||||
this.handlerMapping = new RequestMappingHandlerMapping();
|
this.handlerMapping = new TestRequestMappingInfoHandlerMapping();
|
||||||
this.request = new MockHttpServletRequest();
|
this.request = new MockHttpServletRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,5 +151,18 @@ public class RequestMappingInfoComparatorTests {
|
|||||||
assertTrue(comparator.compare(html, xml) > 0);
|
assertTrue(comparator.compare(html, xml) > 0);
|
||||||
assertTrue(comparator.compare(xml, html) < 0);
|
assertTrue(comparator.compare(xml, html) < 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TestRequestMappingInfoHandlerMapping extends RequestMappingInfoHandlerMapping {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isHandler(Class<?> beanType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.web.servlet.mvc.method.annotation;
|
package org.springframework.web.servlet.mvc.method;
|
||||||
|
|
||||||
import static org.junit.Assert.assertArrayEquals;
|
import static org.junit.Assert.assertArrayEquals;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -23,12 +23,14 @@ import static org.junit.Assert.assertNull;
|
|||||||
import static org.junit.Assert.assertSame;
|
import static org.junit.Assert.assertSame;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.context.support.StaticApplicationContext;
|
import org.springframework.context.support.StaticApplicationContext;
|
||||||
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.mock.web.MockHttpServletRequest;
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
@@ -40,6 +42,9 @@ 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.servlet.mvc.method.RequestMappingInfo;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
|
||||||
import org.springframework.web.util.UrlPathHelper;
|
import org.springframework.web.util.UrlPathHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,9 +53,9 @@ import org.springframework.web.util.UrlPathHelper;
|
|||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
*/
|
*/
|
||||||
public class RequestMappingHandlerMappingTests {
|
public class RequestMappingInfoHandlerMappingTests {
|
||||||
|
|
||||||
private RequestMappingHandlerMapping mapping;
|
private TestRequestMappingInfoHandlerMapping mapping;
|
||||||
|
|
||||||
private Handler handler;
|
private Handler handler;
|
||||||
|
|
||||||
@@ -73,7 +78,7 @@ public class RequestMappingHandlerMappingTests {
|
|||||||
StaticApplicationContext context = new StaticApplicationContext();
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
context.registerSingleton("handler", handler.getClass());
|
context.registerSingleton("handler", handler.getClass());
|
||||||
|
|
||||||
mapping = new RequestMappingHandlerMapping();
|
mapping = new TestRequestMappingInfoHandlerMapping();
|
||||||
mapping.setApplicationContext(context);
|
mapping.setApplicationContext(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +153,7 @@ public class RequestMappingHandlerMappingTests {
|
|||||||
StaticApplicationContext context = new StaticApplicationContext();
|
StaticApplicationContext context = new StaticApplicationContext();
|
||||||
context.registerSingleton("handler", handler.getClass());
|
context.registerSingleton("handler", handler.getClass());
|
||||||
|
|
||||||
mapping = new RequestMappingHandlerMapping();
|
mapping = new TestRequestMappingInfoHandlerMapping();
|
||||||
mapping.setInterceptors(new Object[] { mappedInterceptor });
|
mapping.setInterceptors(new Object[] { mappedInterceptor });
|
||||||
mapping.setApplicationContext(context);
|
mapping.setApplicationContext(context);
|
||||||
|
|
||||||
@@ -163,7 +168,6 @@ public class RequestMappingHandlerMappingTests {
|
|||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping
|
|
||||||
private static class Handler {
|
private static class Handler {
|
||||||
|
|
||||||
@RequestMapping(value = "/foo", method = RequestMethod.GET)
|
@RequestMapping(value = "/foo", method = RequestMethod.GET)
|
||||||
@@ -182,5 +186,24 @@ public class RequestMappingHandlerMappingTests {
|
|||||||
public void empty() {
|
public void empty() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TestRequestMappingInfoHandlerMapping extends RequestMappingInfoHandlerMapping {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isHandler(Class<?> beanType) {
|
||||||
|
return AnnotationUtils.findAnnotation(beanType, Controller.class) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
|
||||||
|
RequestMapping annotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||||
|
return new RequestMappingInfo(Arrays.asList(annotation.value()),
|
||||||
|
RequestConditionFactory.parseMethods(annotation.method()),
|
||||||
|
RequestConditionFactory.parseParams(annotation.params()),
|
||||||
|
RequestConditionFactory.parseHeaders(annotation.headers()),
|
||||||
|
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()),
|
||||||
|
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.springframework.web.servlet.mvc.method.annotation;
|
package org.springframework.web.servlet.mvc.method;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@ 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.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||||
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;
|
||||||
|
|
||||||
Reference in New Issue
Block a user