diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HandlerMapping.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HandlerMapping.java index 76e37463089..c95e6ede0f9 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HandlerMapping.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/HandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2007 the original author or authors. + * Copyright 2002-2010 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. @@ -74,6 +74,14 @@ public interface HandlerMapping { */ String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern"; + /** + * Name of the boolean {@link HttpServletRequest} attribute that indicates + * whether type-level mappings should be inspected. + *
Note: This attribute is not required to be supported by all + * HandlerMapping implementations. + */ + String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping"; + /** * Name of the {@link HttpServletRequest} attribute that contains the URI * templates map, mapping variable names to values. diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java index 8d80909d379..f9623c76d47 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractUrlHandlerMapping.java @@ -429,6 +429,13 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { return Collections.unmodifiableMap(this.handlerMap); } + /** + * Indicates whether this handler mapping support type-level mappings. Default to {@code false}. + */ + protected boolean supportsTypeLevelMappings() { + return false; + } + /** * Special interceptor for exposing the @@ -449,10 +456,11 @@ public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request); + request.setAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING, supportsTypeLevelMappings()); return true; } - } + } /** * Special interceptor for exposing the diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index 328288a1b1c..a1156798b08 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -34,7 +34,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; - import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -45,6 +44,7 @@ import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; @@ -571,6 +571,27 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator } mappingInfo.sortMatchedPatterns(pathComparator); } + else if (useTypeLevelMapping(request)) { + String[] typeLevelPatterns = getTypeLevelMapping().value(); + for (String typeLevelPattern : typeLevelPatterns) { + if (!typeLevelPattern.startsWith("/")) { + typeLevelPattern = "/" + typeLevelPattern; + } + if (isPathMatchInternal(typeLevelPattern, lookupPath)) { + if (mappingInfo.matches(request)) { + match = true; + mappingInfo.addMatchedPattern(typeLevelPattern); + } + else { + if (!mappingInfo.matchesRequestMethod(request)) { + allowedMethods.addAll(mappingInfo.methodNames()); + } + break; + } + } + } + mappingInfo.sortMatchedPatterns(pathComparator); + } else { // No paths specified: parameter match sufficient. match = mappingInfo.matches(request); @@ -638,6 +659,14 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator } } + private boolean useTypeLevelMapping(HttpServletRequest request) { + if (!hasTypeLevelMapping() || ObjectUtils.isEmpty(getTypeLevelMapping().value())) { + return false; + } + return (Boolean) request.getAttribute( + HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING); + } + /** * Determines the combined pattern for the given methodLevelPattern and path. *
Uses the following algorithm: