diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java index ae22662d626..cec5b1d60ca 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParser.java @@ -77,7 +77,7 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv /** * A {@link BeanDefinitionParser} that provides the configuration for the - * {@code } MVC namespace element. + * {@code } MVC namespace element. * *

This class registers the following {@link HandlerMapping}s:

* + * + *

This class registers an {@link org.springframework.util.AntPathMatcher} + * and a {@link org.springframework.web.util.UrlPathHelper} to be used by: + *

+ * Note that those beans can be configured by using the {@code path-matching} MVC namespace element. + * *

Both the {@link RequestMappingHandlerAdapter} and the * {@link ExceptionHandlerExceptionResolver} are configured with instances of @@ -174,7 +184,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { handlerMappingDef.getPropertyValues().add("removeSemicolonContent", !enableMatrixVariables); } - configurePathMatchingProperties(handlerMappingDef, element); + configurePathMatchingProperties(handlerMappingDef, element, parserContext); RuntimeBeanReference conversionService = getConversionService(element, source, parserContext); RuntimeBeanReference validator = getValidator(element, source, parserContext); @@ -348,9 +358,11 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { return contentNegotiationManagerRef; } - private void configurePathMatchingProperties(RootBeanDefinition handlerMappingDef, Element element) { + private void configurePathMatchingProperties(RootBeanDefinition handlerMappingDef, + Element element, ParserContext parserContext) { Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching"); if(pathMatchingElement != null) { + Object source = parserContext.extractSource(element); if (pathMatchingElement.hasAttribute("suffix-pattern")) { Boolean useSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("suffix-pattern")); handlerMappingDef.getPropertyValues().add("useSuffixPatternMatch", useSuffixPatternMatch); @@ -363,14 +375,19 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser { Boolean useRegisteredSuffixPatternMatch = Boolean.valueOf(pathMatchingElement.getAttribute("registered-suffixes-only")); handlerMappingDef.getPropertyValues().add("useRegisteredSuffixPatternMatch", useRegisteredSuffixPatternMatch); } + RuntimeBeanReference pathHelperRef = null; if (pathMatchingElement.hasAttribute("path-helper")) { - RuntimeBeanReference pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper")); - handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef); + pathHelperRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-helper")); } + pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(pathHelperRef, parserContext, source); + handlerMappingDef.getPropertyValues().add("urlPathHelper", pathHelperRef); + + RuntimeBeanReference pathMatcherRef = null; if (pathMatchingElement.hasAttribute("path-matcher")) { - RuntimeBeanReference pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher")); - handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef); + pathMatcherRef = new RuntimeBeanReference(pathMatchingElement.getAttribute("path-matcher")); } + pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(pathMatcherRef, parserContext, source); + handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef); } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/MvcNamespaceUtils.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/MvcNamespaceUtils.java index abf53b4e2c8..e6c426c1cff 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/MvcNamespaceUtils.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/MvcNamespaceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -17,17 +17,22 @@ package org.springframework.web.servlet.config; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; +import org.springframework.web.util.UrlPathHelper; /** * Convenience methods for use in MVC namespace BeanDefinitionParsers. * * @author Rossen Stoyanchev + * @author Brian Clozel * @since 3.1 */ abstract class MvcNamespaceUtils { @@ -41,12 +46,62 @@ abstract class MvcNamespaceUtils { private static final String HTTP_REQUEST_HANDLER_ADAPTER_BEAN_NAME = HttpRequestHandlerAdapter.class.getName(); + private static final String URL_PATH_HELPER_BEAN_NAME = "mvcUrlPathHelper"; + + private static final String PATH_MATCHER_BEAN_NAME = "mvcPathMatcher"; + public static void registerDefaultComponents(ParserContext parserContext, Object source) { registerBeanNameUrlHandlerMapping(parserContext, source); registerHttpRequestHandlerAdapter(parserContext, source); registerSimpleControllerHandlerAdapter(parserContext, source); } + /** + * Adds an alias to an existing well-known name or registers a new instance of a {@link UrlPathHelper} + * under that well-known name, unless already registered. + * @return a RuntimeBeanReference to this {@link UrlPathHelper} instance + */ + public static RuntimeBeanReference registerUrlPathHelper(RuntimeBeanReference urlPathHelperRef, ParserContext parserContext, Object source) { + if(urlPathHelperRef != null) { + if(parserContext.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME)) { + parserContext.getRegistry().removeAlias(URL_PATH_HELPER_BEAN_NAME); + } + parserContext.getRegistry().registerAlias(urlPathHelperRef.getBeanName(), URL_PATH_HELPER_BEAN_NAME); + } + else if (!parserContext.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME) + && !parserContext.getRegistry().containsBeanDefinition(URL_PATH_HELPER_BEAN_NAME)) { + RootBeanDefinition urlPathHelperDef = new RootBeanDefinition(UrlPathHelper.class); + urlPathHelperDef.setSource(source); + urlPathHelperDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(URL_PATH_HELPER_BEAN_NAME, urlPathHelperDef); + parserContext.registerComponent(new BeanComponentDefinition(urlPathHelperDef, URL_PATH_HELPER_BEAN_NAME)); + } + return new RuntimeBeanReference(URL_PATH_HELPER_BEAN_NAME); + } + + /** + * Adds an alias to an existing well-known name or registers a new instance of a {@link PathMatcher} + * under that well-known name, unless already registered. + * @return a RuntimeBeanReference to this {@link PathMatcher} instance + */ + public static RuntimeBeanReference registerPathMatcher(RuntimeBeanReference pathMatcherRef, ParserContext parserContext, Object source) { + if(pathMatcherRef != null) { + if(parserContext.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME)) { + parserContext.getRegistry().removeAlias(PATH_MATCHER_BEAN_NAME); + } + parserContext.getRegistry().registerAlias(pathMatcherRef.getBeanName(), PATH_MATCHER_BEAN_NAME); + } + else if (!parserContext.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME) + && !parserContext.getRegistry().containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) { + RootBeanDefinition pathMatcherDef = new RootBeanDefinition(AntPathMatcher.class); + pathMatcherDef.setSource(source); + pathMatcherDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(PATH_MATCHER_BEAN_NAME, pathMatcherDef); + parserContext.registerComponent(new BeanComponentDefinition(pathMatcherDef, PATH_MATCHER_BEAN_NAME)); + } + return new RuntimeBeanReference(PATH_MATCHER_BEAN_NAME); + } + /** * Registers an {@link HttpRequestHandlerAdapter} under a well-known * name unless already registered. diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java index f08d75e2b8f..49d7ff0ff5e 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ResourcesBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -22,6 +22,7 @@ import java.util.Map; import org.w3c.dom.Element; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; @@ -63,10 +64,14 @@ class ResourcesBeanDefinitionParser implements BeanDefinitionParser { } urlMap.put(resourceRequestPath, resourceHandlerName); + RuntimeBeanReference pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(null, parserContext, source); + RuntimeBeanReference pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(null, parserContext, source); + RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); handlerMappingDef.setSource(source); handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); handlerMappingDef.getPropertyValues().add("urlMap", urlMap); + handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef).add("urlPathHelper", pathHelperRef); String order = element.getAttribute("order"); // use a default of near-lowest precedence, still allowing for even lower precedence in other mappings diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java index 6ab039507cc..52181a2875f 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/ViewControllerBeanDefinitionParser.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -19,6 +19,7 @@ package org.springframework.web.servlet.config; import java.util.Map; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.support.RootBeanDefinition; @@ -75,9 +76,13 @@ class ViewControllerBeanDefinitionParser implements BeanDefinitionParser { private BeanDefinition registerHandlerMapping(ParserContext parserContext, Object source) { if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_BEAN_NAME)) { + RuntimeBeanReference pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(null, parserContext, source); + RuntimeBeanReference pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(null, parserContext, source); + RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class); handlerMappingDef.setSource(source); handlerMappingDef.getPropertyValues().add("order", "1"); + handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef).add("urlPathHelper", pathHelperRef); handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME, handlerMappingDef); parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME)); diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java index 119c0d8fa31..dbede71a53a 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/PathMatchConfigurer.java @@ -20,12 +20,19 @@ import org.springframework.util.PathMatcher; import org.springframework.web.util.UrlPathHelper; /** - * Helps with configuring {@link org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping} - * path matching options such as trailing slash match, suffix registration or path matcher/helper. + * Helps with configuring HandlerMappings path matching options such as trailing slash match, + * suffix registration, path matcher and path helper. + * Configured path matcher and path helper instances are shared for: + *

* * @author Brian Clozel * @since 4.0.3 * @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping + * @see org.springframework.web.servlet.handler.SimpleUrlHandlerMapping */ public class PathMatchConfigurer { @@ -101,7 +108,6 @@ public class PathMatchConfigurer { return this; } - public Boolean isUseSuffixPatternMatch() { return this.useSuffixPatternMatch; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java index 896abadeffd..99e0785fbe4 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java @@ -48,6 +48,7 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter; import org.springframework.http.converter.xml.SourceHttpMessageConverter; +import org.springframework.util.AntPathMatcher; import org.springframework.util.ClassUtils; import org.springframework.util.PathMatcher; import org.springframework.validation.Errors; @@ -128,6 +129,15 @@ import org.springframework.web.util.UrlPathHelper; * exception types * * + *

Registers an {@link AntPathMatcher} and a {@link UrlPathHelper} + * to be used by: + *

+ * Note that those beans can be configured with a {@link PathMatchConfigurer}. + * *

Both the {@link RequestMappingHandlerAdapter} and the * {@link ExceptionHandlerExceptionResolver} are configured with default * instances of the following by default: @@ -145,6 +155,7 @@ import org.springframework.web.util.UrlPathHelper; * @see WebMvcConfigurerAdapter * * @author Rossen Stoyanchev + * @author Brian Clozel * @since 3.1 */ public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware { @@ -318,6 +329,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping(); + handlerMapping.setPathMatcher(mvcPathMatcher()); + handlerMapping.setUrlPathHelper(mvcUrlPathHelper()); handlerMapping.setInterceptors(getInterceptors()); return handlerMapping; } @@ -353,6 +366,8 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); handlerMapping = handlerMapping != null ? handlerMapping : new EmptyHandlerMapping(); + handlerMapping.setPathMatcher(mvcPathMatcher()); + handlerMapping.setUrlPathHelper(mvcUrlPathHelper()); return handlerMapping; } @@ -509,6 +524,40 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv return validator; } + /** + * Return a global {@link PathMatcher} instance for path matching + * patterns in {@link HandlerMapping}s. + * This instance can be configured using the {@link PathMatchConfigurer} + * in {@link #configurePathMatch(PathMatchConfigurer)}. + * @since 4.1 + */ + @Bean + public PathMatcher mvcPathMatcher() { + if(getPathMatchConfigurer().getPathMatcher() != null) { + return getPathMatchConfigurer().getPathMatcher(); + } + else { + return new AntPathMatcher(); + } + } + + /** + * Return a global {@link UrlPathHelper} instance for path matching + * patterns in {@link HandlerMapping}s. + * This instance can be configured using the {@link PathMatchConfigurer} + * in {@link #configurePathMatch(PathMatchConfigurer)}. + * @since 4.1 + */ + @Bean + public UrlPathHelper mvcUrlPathHelper() { + if(getPathMatchConfigurer().getUrlPathHelper() != null) { + return getPathMatchConfigurer().getUrlPathHelper(); + } + else { + return new UrlPathHelper(); + } + } + /** * Override this method to provide a custom {@link Validator}. */ diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java index a65b6326e8c..6af00bf29b9 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java @@ -80,7 +80,14 @@ public interface WebMvcConfigurer { void configureAsyncSupport(AsyncSupportConfigurer configurer); /** - * Configure path matching options. + * Helps with configuring HandlerMappings path matching options such as trailing slash match, + * suffix registration, path matcher and path helper. + * Configured path matcher and path helper instances are shared for: + *

* @since 4.0.3 */ void configurePathMatch(PathMatchConfigurer configurer); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java index 389b76b7fa7..ae84f944655 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -76,6 +76,7 @@ import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBui import org.springframework.web.servlet.resource.DefaultServletHttpRequestHandler; import org.springframework.web.servlet.resource.ResourceHttpRequestHandler; import org.springframework.web.servlet.theme.ThemeChangeInterceptor; +import org.springframework.web.util.UrlPathHelper; import static org.junit.Assert.*; @@ -86,6 +87,8 @@ import static org.junit.Assert.*; */ public class MvcNamespaceTests { + public static final String VIEWCONTROLLER_BEAN_NAME = "org.springframework.web.servlet.config.viewControllerHandlerMapping"; + private GenericWebApplicationContext appContext; private TestController handler; @@ -250,7 +253,7 @@ public class MvcNamespaceTests { @Test public void testResources() throws Exception { - loadBeanDefinitions("mvc-config-resources.xml", 5); + loadBeanDefinitions("mvc-config-resources.xml", 7); HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class); assertNotNull(adapter); @@ -283,7 +286,7 @@ public class MvcNamespaceTests { @Test public void testResourcesWithOptionalAttributes() throws Exception { - loadBeanDefinitions("mvc-config-resources-optional-attrs.xml", 5); + loadBeanDefinitions("mvc-config-resources-optional-attrs.xml", 7); SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class); assertNotNull(mapping); @@ -365,7 +368,7 @@ public class MvcNamespaceTests { @Test public void testViewControllers() throws Exception { - loadBeanDefinitions("mvc-config-view-controllers.xml", 16); + loadBeanDefinitions("mvc-config-view-controllers.xml", 18); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); @@ -425,7 +428,7 @@ public class MvcNamespaceTests { /** WebSphere gives trailing servlet path slashes by default!! */ @Test public void testViewControllersOnWebSphere() throws Exception { - loadBeanDefinitions("mvc-config-view-controllers.xml", 16); + loadBeanDefinitions("mvc-config-view-controllers.xml", 18); SimpleUrlHandlerMapping mapping2 = appContext.getBean(SimpleUrlHandlerMapping.class); SimpleControllerHandlerAdapter adapter = appContext.getBean(SimpleControllerHandlerAdapter.class); @@ -469,7 +472,7 @@ public class MvcNamespaceTests { @Test public void testViewControllersDefaultConfig() { - loadBeanDefinitions("mvc-config-view-controllers-minimal.xml", 4); + loadBeanDefinitions("mvc-config-view-controllers-minimal.xml", 6); BeanNameUrlHandlerMapping beanNameMapping = appContext.getBean(BeanNameUrlHandlerMapping.class); assertNotNull(beanNameMapping); @@ -508,6 +511,28 @@ public class MvcNamespaceTests { assertEquals(1, deferredResultInterceptors.length); } + @Test + public void testPathMatchingHandlerMappings() throws Exception { + loadBeanDefinitions("mvc-config-path-matching-mappings.xml", 20); + + RequestMappingHandlerMapping requestMapping = appContext.getBean(RequestMappingHandlerMapping.class); + assertNotNull(requestMapping); + assertEquals(TestPathHelper.class, requestMapping.getUrlPathHelper().getClass()); + assertEquals(TestPathMatcher.class, requestMapping.getPathMatcher().getClass()); + + SimpleUrlHandlerMapping viewController = appContext.getBean(VIEWCONTROLLER_BEAN_NAME, SimpleUrlHandlerMapping.class); + assertNotNull(viewController); + assertEquals(TestPathHelper.class, viewController.getUrlPathHelper().getClass()); + assertEquals(TestPathMatcher.class, viewController.getPathMatcher().getClass()); + + for(SimpleUrlHandlerMapping handlerMapping : appContext.getBeansOfType(SimpleUrlHandlerMapping.class).values()) { + assertNotNull(handlerMapping); + assertEquals(TestPathHelper.class, handlerMapping.getUrlPathHelper().getClass()); + assertEquals(TestPathMatcher.class, handlerMapping.getPathMatcher().getClass()); + } + + } + private void loadBeanDefinitions(String fileName, int expectedBeanCount) { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext); @@ -618,4 +643,7 @@ public class MvcNamespaceTests { } } + public static class TestPathHelper extends UrlPathHelper { } + + } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java index 6e49460ab22..c17da91504c 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportExtensionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -35,6 +35,7 @@ import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockServletContext; import org.springframework.scheduling.concurrent.ConcurrentTaskExecutor; import org.springframework.stereotype.Controller; +import org.springframework.util.AntPathMatcher; import org.springframework.validation.BeanPropertyBindingResult; import org.springframework.validation.DefaultMessageCodesResolver; import org.springframework.validation.Errors; @@ -63,6 +64,7 @@ import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor; +import org.springframework.web.util.UrlPathHelper; /** * A test fixture with a sub-class of {@link WebMvcConfigurationSupport} that @@ -93,6 +95,8 @@ public class WebMvcConfigurationSupportExtensionTests { RequestMappingHandlerMapping rmHandlerMapping = webConfig.requestMappingHandlerMapping(); rmHandlerMapping.setApplicationContext(webAppContext); rmHandlerMapping.afterPropertiesSet(); + assertEquals(TestPathHelper.class, rmHandlerMapping.getUrlPathHelper().getClass()); + assertEquals(TestPathMatcher.class, rmHandlerMapping.getPathMatcher().getClass()); HandlerExecutionChain chain = rmHandlerMapping.getHandler(new MockHttpServletRequest("GET", "/")); assertNotNull(chain.getInterceptors()); assertEquals(3, chain.getInterceptors().length); @@ -104,6 +108,8 @@ public class WebMvcConfigurationSupportExtensionTests { handlerMapping.setApplicationContext(webAppContext); assertNotNull(handlerMapping); assertEquals(1, handlerMapping.getOrder()); + assertEquals(TestPathHelper.class, handlerMapping.getUrlPathHelper().getClass()); + assertEquals(TestPathMatcher.class, handlerMapping.getPathMatcher().getClass()); HandlerExecutionChain handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/path")); assertNotNull(handler.getHandler()); @@ -111,6 +117,8 @@ public class WebMvcConfigurationSupportExtensionTests { handlerMapping.setApplicationContext(webAppContext); assertNotNull(handlerMapping); assertEquals(Integer.MAX_VALUE-1, handlerMapping.getOrder()); + assertEquals(TestPathHelper.class, handlerMapping.getUrlPathHelper().getClass()); + assertEquals(TestPathMatcher.class, handlerMapping.getPathMatcher().getClass()); handler = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/resources/foo.gif")); assertNotNull(handler.getHandler()); @@ -277,6 +285,12 @@ public class WebMvcConfigurationSupportExtensionTests { exceptionResolvers.add(new SimpleMappingExceptionResolver()); } + @Override + public void configurePathMatch(PathMatchConfigurer configurer) { + configurer.setPathMatcher(new TestPathMatcher()); + configurer.setUrlPathHelper(new TestPathHelper()); + } + @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LocaleChangeInterceptor()); @@ -310,4 +324,7 @@ public class WebMvcConfigurationSupportExtensionTests { } + private class TestPathHelper extends UrlPathHelper {} + + private class TestPathMatcher extends AntPathMatcher {} } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java index a5180e4b54b..7d513d08972 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupportTests.java @@ -36,6 +36,8 @@ import org.springframework.http.HttpEntity; import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockServletContext; import org.springframework.stereotype.Controller; +import org.springframework.util.AntPathMatcher; +import org.springframework.util.PathMatcher; import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.annotation.PathVariable; @@ -58,6 +60,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor; +import org.springframework.web.util.UrlPathHelper; import static org.junit.Assert.*; @@ -197,6 +200,16 @@ public class WebMvcConfigurationSupportTests { assertEquals(JsonViewResponseBodyAdvice.class, interceptors.get(0).getClass()); } + @Test + public void defaultPathMatchConfiguration() throws Exception { + UrlPathHelper urlPathHelper = this.wac.getBean(UrlPathHelper.class); + PathMatcher pathMatcher = this.wac.getBean(PathMatcher.class); + + assertNotNull(urlPathHelper); + assertNotNull(pathMatcher); + assertEquals(AntPathMatcher.class, pathMatcher.getClass()); + } + @EnableWebMvc @Configuration diff --git a/spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-path-matching-mappings.xml b/spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-path-matching-mappings.xml new file mode 100644 index 00000000000..875672b2f4a --- /dev/null +++ b/spring-webmvc/src/test/resources/org/springframework/web/servlet/config/mvc-config-path-matching-mappings.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + \ No newline at end of file