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 3222253e33..966925f77d 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 @@ -29,6 +29,7 @@ import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; import org.springframework.web.util.UrlPathHelper; @@ -57,11 +58,14 @@ abstract class MvcNamespaceUtils { private static final String CORS_CONFIGURATION_BEAN_NAME = "mvcCorsConfigurations"; + private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector"; + public static void registerDefaultComponents(ParserContext parserContext, @Nullable Object source) { registerBeanNameUrlHandlerMapping(parserContext, source); registerHttpRequestHandlerAdapter(parserContext, source); registerSimpleControllerHandlerAdapter(parserContext, source); + registerHandlerMappingIntrospector(parserContext, source); } /** @@ -186,6 +190,21 @@ abstract class MvcNamespaceUtils { return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME); } + /** + * Registers an {@link HandlerMappingIntrospector} under a well-known name + * unless already registered. + */ + private static void registerHandlerMappingIntrospector(ParserContext parserContext, @Nullable Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)){ + RootBeanDefinition beanDef = new RootBeanDefinition(HandlerMappingIntrospector.class); + beanDef.setSource(source); + beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + beanDef.setLazyInit(true); + parserContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, beanDef); + parserContext.registerComponent(new BeanComponentDefinition(beanDef, HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)); + } + } + /** * Find the {@code ContentNegotiationManager} bean created by or registered * with the {@code annotation-driven} element. 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 30cc566e87..7b726f861c 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 @@ -32,6 +32,7 @@ import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; import org.springframework.core.convert.converter.Converter; import org.springframework.format.Formatter; import org.springframework.format.FormatterRegistry; @@ -82,6 +83,7 @@ import org.springframework.web.servlet.handler.AbstractHandlerMapping; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; @@ -1022,6 +1024,12 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv protected void addCorsMappings(CorsRegistry registry) { } + @Bean @Lazy + public HandlerMappingIntrospector mvcHandlerMappingIntrospector() { + return new HandlerMappingIntrospector(); + } + + private static final class EmptyHandlerMapping extends AbstractHandlerMapping { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java index 905e876955..2d8b1e2429 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/HandlerMappingIntrospector.java @@ -18,20 +18,23 @@ package org.springframework.web.servlet.handler; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; - import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.springframework.beans.factory.BeanFactoryUtils; +import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PropertiesLoaderUtils; import org.springframework.lang.Nullable; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; import org.springframework.web.cors.CorsConfiguration; @@ -56,33 +59,66 @@ import org.springframework.web.servlet.HandlerMapping; * @author Rossen Stoyanchev * @since 4.3.1 */ -public class HandlerMappingIntrospector implements CorsConfigurationSource { +public class HandlerMappingIntrospector + implements CorsConfigurationSource, ApplicationContextAware, InitializingBean { - private final List handlerMappings; + @Nullable + private ApplicationContext applicationContext; + @Nullable + private List handlerMappings; + + + /** + * Constructor for use with {@link ApplicationContextAware}. + */ + public HandlerMappingIntrospector() { + } /** * Constructor that detects the configured {@code HandlerMapping}s in the * given {@code ApplicationContext} or falls back on * "DispatcherServlet.properties" like the {@code DispatcherServlet}. */ + @Deprecated public HandlerMappingIntrospector(ApplicationContext context) { this.handlerMappings = initHandlerMappings(context); } - private static List initHandlerMappings(ApplicationContext context) { + /** + * Return the configured HandlerMapping's. + */ + public List getHandlerMappings() { + return this.handlerMappings; + } + + + @Override + public void setApplicationContext(ApplicationContext applicationContext) { + this.applicationContext = applicationContext; + } + + @Override + public void afterPropertiesSet() { + if (this.handlerMappings == null) { + Assert.notNull(this.applicationContext, "No ApplicationContext"); + this.handlerMappings = initHandlerMappings(this.applicationContext); + } + } + + private static List initHandlerMappings(ApplicationContext applicationContext) { Map beans = BeanFactoryUtils.beansOfTypeIncludingAncestors( - context, HandlerMapping.class, true, false); + applicationContext, HandlerMapping.class, true, false); if (!beans.isEmpty()) { List mappings = new ArrayList<>(beans.values()); AnnotationAwareOrderComparator.sort(mappings); - return mappings; + return Collections.unmodifiableList(mappings); } - return initDefaultHandlerMappings(context); + return Collections.unmodifiableList(initFallback(applicationContext)); } - private static List initDefaultHandlerMappings(ApplicationContext context) { + private static List initFallback(ApplicationContext applicationContext) { Properties props; String path = "DispatcherServlet.properties"; try { @@ -99,7 +135,7 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource { for (String name : names) { try { Class clazz = ClassUtils.forName(name, DispatcherServlet.class.getClassLoader()); - Object mapping = context.getAutowireCapableBeanFactory().createBean(clazz); + Object mapping = applicationContext.getAutowireCapableBeanFactory().createBean(clazz); result.add((HandlerMapping) mapping); } catch (ClassNotFoundException ex) { @@ -110,13 +146,6 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource { } - /** - * Return the configured HandlerMapping's. - */ - public List getHandlerMappings() { - return this.handlerMappings; - } - /** * Find the {@link HandlerMapping} that would handle the given request and * return it as a {@link MatchableHandlerMapping} that can be used to test @@ -129,6 +158,7 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource { */ @Nullable public MatchableHandlerMapping getMatchableHandlerMapping(HttpServletRequest request) throws Exception { + Assert.notNull(this.handlerMappings, "Handler mappings not initialized"); HttpServletRequest wrapper = new RequestAttributeChangeIgnoringWrapper(request); for (HandlerMapping handlerMapping : this.handlerMappings) { Object handler = handlerMapping.getHandler(wrapper); @@ -146,6 +176,7 @@ public class HandlerMappingIntrospector implements CorsConfigurationSource { @Override @Nullable public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { + Assert.notNull(this.handlerMappings, "Handler mappings not initialized"); HttpServletRequest wrapper = new RequestAttributeChangeIgnoringWrapper(request); for (HandlerMapping handlerMapping : this.handlerMappings) { HandlerExecutionChain handler = null; 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 ce87f44a84..8a5b2fc6b3 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 @@ -97,6 +97,7 @@ import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.handler.AbstractHandlerMapping; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; import org.springframework.web.servlet.handler.ConversionServiceExposingInterceptor; +import org.springframework.web.servlet.handler.HandlerMappingIntrospector; import org.springframework.web.servlet.handler.MappedInterceptor; import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping; import org.springframework.web.servlet.handler.UserRoleAuthorizationInterceptor; @@ -194,7 +195,7 @@ public class MvcNamespaceTests { @Test public void testDefaultConfig() throws Exception { - loadBeanDefinitions("mvc-config.xml", 14); + loadBeanDefinitions("mvc-config.xml"); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); @@ -253,11 +254,18 @@ public class MvcNamespaceTests { CompositeUriComponentsContributor.class); assertNotNull(uriComponentsContributor); + + String name = "mvcHandlerMappingIntrospector"; + HandlerMappingIntrospector introspector = this.appContext.getBean(name, HandlerMappingIntrospector.class); + assertNotNull(introspector); + assertEquals(2, introspector.getHandlerMappings().size()); + assertSame(mapping, introspector.getHandlerMappings().get(0)); + assertEquals(BeanNameUrlHandlerMapping.class, introspector.getHandlerMappings().get(1).getClass()); } @Test(expected = TypeMismatchException.class) public void testCustomConversionService() throws Exception { - loadBeanDefinitions("mvc-config-custom-conversion-service.xml", 14); + loadBeanDefinitions("mvc-config-custom-conversion-service.xml"); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); @@ -287,7 +295,7 @@ public class MvcNamespaceTests { } private void doTestCustomValidator(String xml) throws Exception { - loadBeanDefinitions(xml, 14); + loadBeanDefinitions(xml); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); @@ -309,7 +317,7 @@ public class MvcNamespaceTests { @Test public void testInterceptors() throws Exception { - loadBeanDefinitions("mvc-config-interceptors.xml", 18); + loadBeanDefinitions("mvc-config-interceptors.xml"); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); @@ -342,7 +350,7 @@ public class MvcNamespaceTests { @Test public void testResources() throws Exception { - loadBeanDefinitions("mvc-config-resources.xml", 20); + loadBeanDefinitions("mvc-config-resources.xml"); HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class); assertNotNull(adapter); @@ -390,7 +398,7 @@ public class MvcNamespaceTests { @Test public void testResourcesWithOptionalAttributes() throws Exception { - loadBeanDefinitions("mvc-config-resources-optional-attrs.xml", 10); + loadBeanDefinitions("mvc-config-resources-optional-attrs.xml"); SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class); assertNotNull(mapping); @@ -405,7 +413,7 @@ public class MvcNamespaceTests { @Test public void testResourcesWithResolversTransformers() throws Exception { - loadBeanDefinitions("mvc-config-resources-chain.xml", 11); + loadBeanDefinitions("mvc-config-resources-chain.xml"); SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class); assertNotNull(mapping); @@ -444,7 +452,7 @@ public class MvcNamespaceTests { @Test public void testResourcesWithResolversTransformersCustom() throws Exception { - loadBeanDefinitions("mvc-config-resources-chain-no-auto.xml", 12); + loadBeanDefinitions("mvc-config-resources-chain-no-auto.xml"); SimpleUrlHandlerMapping mapping = appContext.getBean(SimpleUrlHandlerMapping.class); assertNotNull(mapping); @@ -477,7 +485,7 @@ public class MvcNamespaceTests { @Test public void testDefaultServletHandler() throws Exception { - loadBeanDefinitions("mvc-config-default-servlet.xml", 6); + loadBeanDefinitions("mvc-config-default-servlet.xml"); HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class); assertNotNull(adapter); @@ -503,7 +511,7 @@ public class MvcNamespaceTests { @Test public void testDefaultServletHandlerWithOptionalAttributes() throws Exception { - loadBeanDefinitions("mvc-config-default-servlet-optional-attrs.xml", 6); + loadBeanDefinitions("mvc-config-default-servlet-optional-attrs.xml"); HttpRequestHandlerAdapter adapter = appContext.getBean(HttpRequestHandlerAdapter.class); assertNotNull(adapter); @@ -529,7 +537,7 @@ public class MvcNamespaceTests { @Test public void testBeanDecoration() throws Exception { - loadBeanDefinitions("mvc-config-bean-decoration.xml", 16); + loadBeanDefinitions("mvc-config-bean-decoration.xml"); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); @@ -550,7 +558,7 @@ public class MvcNamespaceTests { @Test public void testViewControllers() throws Exception { - loadBeanDefinitions("mvc-config-view-controllers.xml", 19); + loadBeanDefinitions("mvc-config-view-controllers.xml"); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(mapping); @@ -631,7 +639,7 @@ public class MvcNamespaceTests { /** WebSphere gives trailing servlet path slashes by default!! */ @Test public void testViewControllersOnWebSphere() throws Exception { - loadBeanDefinitions("mvc-config-view-controllers.xml", 19); + loadBeanDefinitions("mvc-config-view-controllers.xml"); SimpleUrlHandlerMapping mapping2 = appContext.getBean(SimpleUrlHandlerMapping.class); SimpleControllerHandlerAdapter adapter = appContext.getBean(SimpleControllerHandlerAdapter.class); @@ -675,7 +683,7 @@ public class MvcNamespaceTests { @Test public void testViewControllersDefaultConfig() { - loadBeanDefinitions("mvc-config-view-controllers-minimal.xml", 7); + loadBeanDefinitions("mvc-config-view-controllers-minimal.xml"); SimpleUrlHandlerMapping hm = this.appContext.getBean(SimpleUrlHandlerMapping.class); assertNotNull(hm); @@ -698,7 +706,7 @@ public class MvcNamespaceTests { @Test public void testContentNegotiationManager() throws Exception { - loadBeanDefinitions("mvc-config-content-negotiation-manager.xml", 15); + loadBeanDefinitions("mvc-config-content-negotiation-manager.xml"); RequestMappingHandlerMapping mapping = appContext.getBean(RequestMappingHandlerMapping.class); ContentNegotiationManager manager = mapping.getContentNegotiationManager(); @@ -720,7 +728,7 @@ public class MvcNamespaceTests { @Test public void testAsyncSupportOptions() throws Exception { - loadBeanDefinitions("mvc-config-async-support.xml", 15); + loadBeanDefinitions("mvc-config-async-support.xml"); RequestMappingHandlerAdapter adapter = appContext.getBean(RequestMappingHandlerAdapter.class); assertNotNull(adapter); @@ -740,7 +748,7 @@ public class MvcNamespaceTests { @Test public void testViewResolution() throws Exception { - loadBeanDefinitions("mvc-config-view-resolution.xml", 6); + loadBeanDefinitions("mvc-config-view-resolution.xml"); ViewResolverComposite compositeResolver = this.appContext.getBean(ViewResolverComposite.class); assertNotNull(compositeResolver); @@ -819,7 +827,7 @@ public class MvcNamespaceTests { @Test public void testViewResolutionWithContentNegotiation() throws Exception { - loadBeanDefinitions("mvc-config-view-resolution-content-negotiation.xml", 6); + loadBeanDefinitions("mvc-config-view-resolution-content-negotiation.xml"); ViewResolverComposite compositeResolver = this.appContext.getBean(ViewResolverComposite.class); assertNotNull(compositeResolver); @@ -843,7 +851,7 @@ public class MvcNamespaceTests { @Test public void testViewResolutionWithOrderSet() throws Exception { - loadBeanDefinitions("mvc-config-view-resolution-custom-order.xml", 1); + loadBeanDefinitions("mvc-config-view-resolution-custom-order.xml"); ViewResolverComposite compositeResolver = this.appContext.getBean(ViewResolverComposite.class); assertNotNull(compositeResolver); @@ -853,7 +861,7 @@ public class MvcNamespaceTests { @Test public void testPathMatchingHandlerMappings() throws Exception { - loadBeanDefinitions("mvc-config-path-matching-mappings.xml", 23); + loadBeanDefinitions("mvc-config-path-matching-mappings.xml"); RequestMappingHandlerMapping requestMapping = appContext.getBean(RequestMappingHandlerMapping.class); assertNotNull(requestMapping); @@ -874,7 +882,7 @@ public class MvcNamespaceTests { @Test public void testCorsMinimal() throws Exception { - loadBeanDefinitions("mvc-config-cors-minimal.xml", 14); + loadBeanDefinitions("mvc-config-cors-minimal.xml"); String[] beanNames = appContext.getBeanNamesForType(AbstractHandlerMapping.class); assertEquals(2, beanNames.length); @@ -897,7 +905,7 @@ public class MvcNamespaceTests { @Test public void testCors() throws Exception { - loadBeanDefinitions("mvc-config-cors.xml", 14); + loadBeanDefinitions("mvc-config-cors.xml"); String[] beanNames = appContext.getBeanNamesForType(AbstractHandlerMapping.class); assertEquals(2, beanNames.length); @@ -926,12 +934,11 @@ public class MvcNamespaceTests { } - private void loadBeanDefinitions(String fileName, int expectedBeanCount) { + private void loadBeanDefinitions(String fileName) { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(appContext); ClassPathResource resource = new ClassPathResource(fileName, AnnotationDrivenBeanDefinitionParserTests.class); reader.loadBeanDefinitions(resource); String names = Arrays.toString(this.appContext.getBeanDefinitionNames()); - assertEquals("Bean names: " + names, expectedBeanCount, appContext.getBeanDefinitionCount()); appContext.refresh(); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMappingIntrospectorTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMappingIntrospectorTests.java index f7e1099b3c..7981af3884 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMappingIntrospectorTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/handler/HandlerMappingIntrospectorTests.java @@ -31,6 +31,7 @@ import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.context.support.StaticWebApplicationContext; import org.springframework.web.cors.CorsConfiguration; @@ -38,8 +39,10 @@ import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; -import static org.junit.Assert.*; -import static org.springframework.web.servlet.HandlerMapping.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.springframework.web.servlet.HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE; /** * Unit tests for {@link HandlerMappingIntrospector}. @@ -58,7 +61,7 @@ public class HandlerMappingIntrospectorTests { cxt.refresh(); List expected = Arrays.asList(cxt.getBean("hmA"), cxt.getBean("hmB"), cxt.getBean("hmC")); - List actual = new HandlerMappingIntrospector(cxt).getHandlerMappings(); + List actual = getIntrospector(cxt).getHandlerMappings(); assertEquals(expected, actual); } @@ -75,7 +78,7 @@ public class HandlerMappingIntrospectorTests { cxt.refresh(); List expected = Arrays.asList(cxt.getBean("hmC"), cxt.getBean("hmB"), cxt.getBean("hmA")); - List actual = new HandlerMappingIntrospector(cxt).getHandlerMappings(); + List actual = getIntrospector(cxt).getHandlerMappings(); assertEquals(expected, actual); } @@ -85,7 +88,7 @@ public class HandlerMappingIntrospectorTests { StaticWebApplicationContext cxt = new StaticWebApplicationContext(); cxt.refresh(); - List actual = new HandlerMappingIntrospector(cxt).getHandlerMappings(); + List actual = getIntrospector(cxt).getHandlerMappings(); assertEquals(2, actual.size()); assertEquals(BeanNameUrlHandlerMapping.class, actual.get(0).getClass()); assertEquals(RequestMappingHandlerMapping.class, actual.get(1).getClass()); @@ -101,7 +104,7 @@ public class HandlerMappingIntrospectorTests { cxt.refresh(); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/path"); - MatchableHandlerMapping hm = new HandlerMappingIntrospector(cxt).getMatchableHandlerMapping(request); + MatchableHandlerMapping hm = getIntrospector(cxt).getMatchableHandlerMapping(request); assertEquals(cxt.getBean("hm"), hm); assertNull("Attributes changes not ignored", request.getAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE)); @@ -114,7 +117,7 @@ public class HandlerMappingIntrospectorTests { cxt.refresh(); MockHttpServletRequest request = new MockHttpServletRequest(); - new HandlerMappingIntrospector(cxt).getMatchableHandlerMapping(request); + getIntrospector(cxt).getMatchableHandlerMapping(request); } @Test @@ -128,7 +131,7 @@ public class HandlerMappingIntrospectorTests { MockHttpServletRequest request = new MockHttpServletRequest("OPTIONS", "/path"); request.addHeader("Origin", "http://localhost:9000"); request.addHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "POST"); - CorsConfiguration corsConfig = new HandlerMappingIntrospector(cxt).getCorsConfiguration(request); + CorsConfiguration corsConfig = getIntrospector(cxt).getCorsConfiguration(request); assertNotNull(corsConfig); assertEquals(Collections.singletonList("http://localhost:9000"), corsConfig.getAllowedOrigins()); @@ -143,13 +146,20 @@ public class HandlerMappingIntrospectorTests { MockHttpServletRequest request = new MockHttpServletRequest("POST", "/path"); request.addHeader("Origin", "http://localhost:9000"); - CorsConfiguration corsConfig = new HandlerMappingIntrospector(cxt).getCorsConfiguration(request); + CorsConfiguration corsConfig = getIntrospector(cxt).getCorsConfiguration(request); assertNotNull(corsConfig); assertEquals(Collections.singletonList("http://localhost:9000"), corsConfig.getAllowedOrigins()); assertEquals(Collections.singletonList("POST"), corsConfig.getAllowedMethods()); } + private HandlerMappingIntrospector getIntrospector(WebApplicationContext cxt) { + HandlerMappingIntrospector introspector = new HandlerMappingIntrospector(); + introspector.setApplicationContext(cxt); + introspector.afterPropertiesSet(); + return introspector; + } + private static class TestHandlerMapping implements HandlerMapping {