diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java index 40efb17d53c3..a47814c501bf 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java @@ -27,6 +27,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; +import org.springframework.beans.factory.BeanFactoryUtils; import org.springframework.context.ApplicationContextException; import org.springframework.util.ClassUtils; import org.springframework.util.LinkedMultiValueMap; @@ -52,10 +53,24 @@ */ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMapping { + private boolean detectHandlerMethodsInAncestorContexts = false; + private final Map handlerMethods = new LinkedHashMap(); private final MultiValueMap urlMap = new LinkedMultiValueMap(); + /** + * Whether to detect handler methods in beans in ancestor ApplicationContexts. + *

Default is "false": Only beans in the current ApplicationContext are + * considered, i.e. only in the context that this HandlerMapping itself + * is defined in (typically the current DispatcherServlet's context). + *

Switch this flag on to detect handler beans in ancestor contexts + * (typically the Spring root WebApplicationContext) as well. + */ + public void setDetectHandlerMethodsInAncestorContexts(boolean detectHandlerMethodsInAncestorContexts) { + this.detectHandlerMethodsInAncestorContexts = detectHandlerMethodsInAncestorContexts; + } + /** * Return a map with all handler methods and their mappings. */ @@ -82,7 +97,12 @@ protected void initHandlerMethods() { if (logger.isDebugEnabled()) { logger.debug("Looking for request mappings in application context: " + getApplicationContext()); } - for (String beanName : getApplicationContext().getBeanNamesForType(Object.class)) { + + String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? + BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : + getApplicationContext().getBeanNamesForType(Object.class)); + + for (String beanName : beanNames) { if (isHandler(getApplicationContext().getType(beanName))){ detectHandlerMethods(beanName); } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java index 10bdb33ab10a..755eb6a62d0e 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/handler/HandlerMethodMappingTests.java @@ -27,9 +27,12 @@ import org.junit.Before; import org.junit.Test; +import org.springframework.context.support.StaticApplicationContext; import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.stereotype.Controller; import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.method.HandlerMethod; import org.springframework.web.util.UrlPathHelper; @@ -88,6 +91,24 @@ public void ambiguousMatch() throws Exception { mapping.getHandlerInternal(new MockHttpServletRequest("GET", "/foo")); } + @Test + public void testDetectHandlerMethodsInAncestorContexts() { + StaticApplicationContext cxt = new StaticApplicationContext(); + cxt.registerSingleton("myHandler", MyHandler.class); + + AbstractHandlerMethodMapping mapping1 = new MyHandlerMethodMapping(); + mapping1.setApplicationContext(new StaticApplicationContext(cxt)); + + assertEquals(0, mapping1.getHandlerMethods().size()); + + AbstractHandlerMethodMapping mapping2 = new MyHandlerMethodMapping(); + mapping2.setDetectHandlerMethodsInAncestorContexts(true); + mapping2.setApplicationContext(new StaticApplicationContext(cxt)); + + assertEquals(2, mapping2.getHandlerMethods().size()); + } + + private static class MyHandlerMethodMapping extends AbstractHandlerMethodMapping { private UrlPathHelper pathHelper = new UrlPathHelper(); @@ -123,13 +144,14 @@ protected Set getMappingPathPatterns(String key) { } } - private static class MyHandler { + @Controller + static class MyHandler { - @SuppressWarnings("unused") + @RequestMapping public void handlerMethod1() { } - @SuppressWarnings("unused") + @RequestMapping public void handlerMethod2() { } }