diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java index cc1204d6e794..f03f8f5527a9 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/setup/StandaloneMockMvcBuilder.java @@ -62,6 +62,7 @@ import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import org.springframework.web.servlet.resource.ResourceUrlProvider; import org.springframework.web.servlet.support.SessionFlashMapManager; import org.springframework.web.servlet.theme.FixedThemeResolver; import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator; @@ -374,7 +375,16 @@ private void registerMvcSingletons(StubWebApplicationContext wac) { wac.addBeans(this.controllers); wac.addBeans(this.controllerAdvice); - RequestMappingHandlerMapping hm = config.getHandlerMapping(); + FormattingConversionService mvcConversionService = config.mvcConversionService(); + wac.addBean("mvcConversionService", mvcConversionService); + ResourceUrlProvider resourceUrlProvider = config.mvcResourceUrlProvider(); + wac.addBean("mvcResourceUrlProvider", resourceUrlProvider); + ContentNegotiationManager mvcContentNegotiationManager = config.mvcContentNegotiationManager(); + wac.addBean("mvcContentNegotiationManager", mvcContentNegotiationManager); + Validator mvcValidator = config.mvcValidator(); + wac.addBean("mvcValidator", mvcValidator); + + RequestMappingHandlerMapping hm = config.getHandlerMapping(mvcConversionService, resourceUrlProvider); if (sc != null) { hm.setServletContext(sc); } @@ -382,7 +392,8 @@ private void registerMvcSingletons(StubWebApplicationContext wac) { hm.afterPropertiesSet(); wac.addBean("requestMappingHandlerMapping", hm); - RequestMappingHandlerAdapter ha = config.requestMappingHandlerAdapter(); + RequestMappingHandlerAdapter ha = config.requestMappingHandlerAdapter(mvcContentNegotiationManager, + mvcConversionService, mvcValidator); if (sc != null) { ha.setServletContext(sc); } @@ -390,7 +401,7 @@ private void registerMvcSingletons(StubWebApplicationContext wac) { ha.afterPropertiesSet(); wac.addBean("requestMappingHandlerAdapter", ha); - wac.addBean("handlerExceptionResolver", config.handlerExceptionResolver()); + wac.addBean("handlerExceptionResolver", config.handlerExceptionResolver(mvcContentNegotiationManager)); wac.addBeans(initViewResolvers(wac)); wac.addBean(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, this.localeResolver); @@ -430,13 +441,15 @@ protected Map extendMvcSingletons(@Nullable ServletContext servl /** Using the MVC Java configuration as the starting point for the "standalone" setup. */ private class StandaloneConfiguration extends WebMvcConfigurationSupport { - public RequestMappingHandlerMapping getHandlerMapping() { + public RequestMappingHandlerMapping getHandlerMapping( + FormattingConversionService mvcConversionService, + ResourceUrlProvider mvcResourceUrlProvider) { RequestMappingHandlerMapping handlerMapping = handlerMappingFactory.get(); handlerMapping.setEmbeddedValueResolver(new StaticStringValueResolver(placeholderValues)); handlerMapping.setUseSuffixPatternMatch(useSuffixPatternMatch); handlerMapping.setUseTrailingSlashMatch(useTrailingSlashPatternMatch); handlerMapping.setOrder(0); - handlerMapping.setInterceptors(getInterceptors()); + handlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); if (removeSemicolonContent != null) { handlerMapping.setRemoveSemicolonContent(removeSemicolonContent); } @@ -506,7 +519,7 @@ protected void configureHandlerExceptionResolvers(List } for (HandlerExceptionResolver resolver : handlerExceptionResolvers) { if (resolver instanceof ApplicationContextAware) { - ApplicationContext applicationContext = getApplicationContext(); + ApplicationContext applicationContext = getApplicationContext(); if (applicationContext != null) { ((ApplicationContextAware) resolver).setApplicationContext(applicationContext); } diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.java index 65601ad6b417..3603ee2cdc3b 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/DelegatingWebFluxConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2019 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. diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java index 07e2e62f0ef4..ab99a8d5d1c5 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/config/WebFluxConfigurationSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -92,6 +92,10 @@ public class WebFluxConfigurationSupport implements ApplicationContextAware { @Nullable private ApplicationContext applicationContext; + @Nullable + public final ApplicationContext getApplicationContext() { + return this.applicationContext; + } @Override public void setApplicationContext(@Nullable ApplicationContext applicationContext) { @@ -103,12 +107,6 @@ public void setApplicationContext(@Nullable ApplicationContext applicationContex } } - @Nullable - public final ApplicationContext getApplicationContext() { - return this.applicationContext; - } - - @Bean public DispatcherHandler webHandler() { return new DispatcherHandler(); @@ -121,10 +119,11 @@ public WebExceptionHandler responseStatusExceptionHandler() { } @Bean - public RequestMappingHandlerMapping requestMappingHandlerMapping() { + public RequestMappingHandlerMapping requestMappingHandlerMapping( + RequestedContentTypeResolver webFluxContentTypeResolver) { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); mapping.setOrder(0); - mapping.setContentTypeResolver(webFluxContentTypeResolver()); + mapping.setContentTypeResolver(webFluxContentTypeResolver); mapping.setCorsConfigurations(getCorsConfigurations()); PathMatchConfigurer configurer = getPathMatchConfigurer(); @@ -203,10 +202,10 @@ public void configurePathMatching(PathMatchConfigurer configurer) { } @Bean - public RouterFunctionMapping routerFunctionMapping() { + public RouterFunctionMapping routerFunctionMapping(ServerCodecConfigurer serverCodecConfigurer) { RouterFunctionMapping mapping = createRouterFunctionMapping(); mapping.setOrder(-1); // go before RequestMappingHandlerMapping - mapping.setMessageReaders(serverCodecConfigurer().getReaders()); + mapping.setMessageReaders(serverCodecConfigurer.getReaders()); mapping.setCorsConfigurations(getCorsConfigurations()); return mapping; @@ -225,13 +224,13 @@ protected RouterFunctionMapping createRouterFunctionMapping() { * {@link #addResourceHandlers}. */ @Bean - public HandlerMapping resourceHandlerMapping() { + public HandlerMapping resourceHandlerMapping(ResourceUrlProvider resourceUrlProvider) { ResourceLoader resourceLoader = this.applicationContext; if (resourceLoader == null) { resourceLoader = new DefaultResourceLoader(); } ResourceHandlerRegistry registry = new ResourceHandlerRegistry(resourceLoader); - registry.setResourceUrlProvider(resourceUrlProvider()); + registry.setResourceUrlProvider(resourceUrlProvider); addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); @@ -265,11 +264,15 @@ protected void addResourceHandlers(ResourceHandlerRegistry registry) { } @Bean - public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { + public RequestMappingHandlerAdapter requestMappingHandlerAdapter( + ReactiveAdapterRegistry webFluxAdapterRegistry, + ServerCodecConfigurer serverCodecConfigurer, + FormattingConversionService webFluxConversionService, + Validator webfluxValidator) { RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); - adapter.setMessageReaders(serverCodecConfigurer().getReaders()); - adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); - adapter.setReactiveAdapterRegistry(webFluxAdapterRegistry()); + adapter.setMessageReaders(serverCodecConfigurer.getReaders()); + adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(webFluxConversionService, webfluxValidator)); + adapter.setReactiveAdapterRegistry(webFluxAdapterRegistry); ArgumentResolverConfigurer configurer = new ArgumentResolverConfigurer(); configureArgumentResolvers(configurer); @@ -325,10 +328,12 @@ protected void configureHttpMessageCodecs(ServerCodecConfigurer configurer) { * Return the {@link ConfigurableWebBindingInitializer} to use for * initializing all {@link WebDataBinder} instances. */ - protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() { + protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer( + FormattingConversionService webFluxConversionService, + Validator webFluxValidator) { ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); - initializer.setConversionService(webFluxConversionService()); - initializer.setValidator(webFluxValidator()); + initializer.setConversionService(webFluxConversionService); + initializer.setValidator(webFluxValidator); MessageCodesResolver messageCodesResolver = getMessageCodesResolver(); if (messageCodesResolver != null) { initializer.setMessageCodesResolver(messageCodesResolver); @@ -420,33 +425,42 @@ public SimpleHandlerAdapter simpleHandlerAdapter() { } @Bean - public ResponseEntityResultHandler responseEntityResultHandler() { - return new ResponseEntityResultHandler(serverCodecConfigurer().getWriters(), - webFluxContentTypeResolver(), webFluxAdapterRegistry()); + public ResponseEntityResultHandler responseEntityResultHandler( + ReactiveAdapterRegistry webFluxAdapterRegistry, + ServerCodecConfigurer serverCodecConfigurer, + RequestedContentTypeResolver webFluxContentTypeResolver) { + return new ResponseEntityResultHandler(serverCodecConfigurer.getWriters(), + webFluxContentTypeResolver, webFluxAdapterRegistry); } @Bean - public ResponseBodyResultHandler responseBodyResultHandler() { - return new ResponseBodyResultHandler(serverCodecConfigurer().getWriters(), - webFluxContentTypeResolver(), webFluxAdapterRegistry()); + public ResponseBodyResultHandler responseBodyResultHandler( + ReactiveAdapterRegistry webFluxAdapterRegistry, + ServerCodecConfigurer serverCodecConfigurer, + RequestedContentTypeResolver webFluxContentTypeResolver) { + return new ResponseBodyResultHandler(serverCodecConfigurer.getWriters(), + webFluxContentTypeResolver, webFluxAdapterRegistry); } @Bean - public ViewResolutionResultHandler viewResolutionResultHandler() { + public ViewResolutionResultHandler viewResolutionResultHandler( + ReactiveAdapterRegistry webFluxAdapterRegistry, + RequestedContentTypeResolver webFluxContentTypeResolver) { ViewResolverRegistry registry = getViewResolverRegistry(); List resolvers = registry.getViewResolvers(); ViewResolutionResultHandler handler = new ViewResolutionResultHandler( - resolvers, webFluxContentTypeResolver(), webFluxAdapterRegistry()); + resolvers, webFluxContentTypeResolver, webFluxAdapterRegistry); handler.setDefaultViews(registry.getDefaultViews()); handler.setOrder(registry.getOrder()); return handler; } @Bean - public ServerResponseResultHandler serverResponseResultHandler() { + public ServerResponseResultHandler serverResponseResultHandler( + ServerCodecConfigurer serverCodecConfigurer) { List resolvers = getViewResolverRegistry().getViewResolvers(); ServerResponseResultHandler handler = new ServerResponseResultHandler(); - handler.setMessageWriters(serverCodecConfigurer().getWriters()); + handler.setMessageWriters(serverCodecConfigurer.getWriters()); handler.setViewResolvers(resolvers); return handler; } diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java index 96098a290944..bac0c180f596 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/config/DelegatingWebFluxConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 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. @@ -27,9 +27,12 @@ import org.mockito.MockitoAnnotations; import org.springframework.context.support.StaticApplicationContext; +import org.springframework.core.ReactiveAdapterRegistry; import org.springframework.format.FormatterRegistry; +import org.springframework.format.support.FormattingConversionService; import org.springframework.http.codec.HttpMessageWriter; import org.springframework.http.codec.ServerCodecConfigurer; +import org.springframework.validation.Validator; import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean; import org.springframework.web.bind.support.ConfigurableWebBindingInitializer; import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder; @@ -72,7 +75,7 @@ public void setup() { @Test public void requestMappingHandlerMapping() throws Exception { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); - delegatingConfig.requestMappingHandlerMapping(); + delegatingConfig.requestMappingHandlerMapping(delegatingConfig.webFluxContentTypeResolver()); verify(webFluxConfigurer).configureContentTypeResolver(any(RequestedContentTypeResolverBuilder.class)); verify(webFluxConfigurer).addCorsMappings(any(CorsRegistry.class)); @@ -82,9 +85,14 @@ public void requestMappingHandlerMapping() throws Exception { @Test public void requestMappingHandlerAdapter() throws Exception { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); + ReactiveAdapterRegistry reactiveAdapterRegistry = delegatingConfig.webFluxAdapterRegistry(); + ServerCodecConfigurer serverCodecConfigurer = delegatingConfig.serverCodecConfigurer(); + FormattingConversionService formattingConversionService = delegatingConfig.webFluxConversionService(); + Validator validator = delegatingConfig.webFluxValidator(); ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) - this.delegatingConfig.requestMappingHandlerAdapter().getWebBindingInitializer(); + this.delegatingConfig.requestMappingHandlerAdapter(reactiveAdapterRegistry, serverCodecConfigurer, + formattingConversionService, validator).getWebBindingInitializer(); verify(webFluxConfigurer).configureHttpMessageCodecs(codecsConfigurer.capture()); verify(webFluxConfigurer).getValidator(); @@ -107,7 +115,7 @@ public void resourceHandlerMapping() throws Exception { return null; }).when(webFluxConfigurer).addResourceHandlers(any(ResourceHandlerRegistry.class)); - delegatingConfig.resourceHandlerMapping(); + delegatingConfig.resourceHandlerMapping(delegatingConfig.resourceUrlProvider()); verify(webFluxConfigurer).addResourceHandlers(any(ResourceHandlerRegistry.class)); verify(webFluxConfigurer).configurePathMatching(any(PathMatchConfigurer.class)); } @@ -115,7 +123,10 @@ public void resourceHandlerMapping() throws Exception { @Test public void responseBodyResultHandler() throws Exception { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); - delegatingConfig.responseBodyResultHandler(); + delegatingConfig.responseBodyResultHandler( + delegatingConfig.webFluxAdapterRegistry(), + delegatingConfig.serverCodecConfigurer(), + delegatingConfig.webFluxContentTypeResolver()); verify(webFluxConfigurer).configureHttpMessageCodecs(codecsConfigurer.capture()); verify(webFluxConfigurer).configureContentTypeResolver(any(RequestedContentTypeResolverBuilder.class)); @@ -124,7 +135,8 @@ public void responseBodyResultHandler() throws Exception { @Test public void viewResolutionResultHandler() throws Exception { delegatingConfig.setConfigurers(Collections.singletonList(webFluxConfigurer)); - delegatingConfig.viewResolutionResultHandler(); + delegatingConfig.viewResolutionResultHandler(delegatingConfig.webFluxAdapterRegistry(), + delegatingConfig.webFluxContentTypeResolver()); verify(webFluxConfigurer).configureViewResolvers(any(ViewResolverRegistry.class)); } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java index 79272309e718..bcdc65c5b374 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * Copyright 2002-2019 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. 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 292e31cdb102..a785da4f9ca4 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 @@ -195,7 +195,7 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader); jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader); jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) && - ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); + ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader); jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader); jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader); jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader); @@ -273,11 +273,14 @@ public final ServletContext getServletContext() { * requests to annotated controllers. */ @Bean - public RequestMappingHandlerMapping requestMappingHandlerMapping() { + public RequestMappingHandlerMapping requestMappingHandlerMapping( + ContentNegotiationManager mvcContentNegotiationManager, + FormattingConversionService mvcConversionService, + ResourceUrlProvider mvcResourceUrlProvider) { RequestMappingHandlerMapping mapping = createRequestMappingHandlerMapping(); mapping.setOrder(0); - mapping.setInterceptors(getInterceptors()); - mapping.setContentNegotiationManager(mvcContentNegotiationManager()); + mapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); + mapping.setContentNegotiationManager(mvcContentNegotiationManager); mapping.setCorsConfigurations(getCorsConfigurations()); PathMatchConfigurer configurer = getPathMatchConfigurer(); @@ -325,12 +328,14 @@ protected RequestMappingHandlerMapping createRequestMappingHandlerMapping() { * {@link HandlerMapping} instances with. *

This method cannot be overridden; use {@link #addInterceptors} instead. */ - protected final Object[] getInterceptors() { + protected final Object[] getInterceptors( + FormattingConversionService mvcConversionService, + ResourceUrlProvider mvcResourceUrlProvider) { if (this.interceptors == null) { InterceptorRegistry registry = new InterceptorRegistry(); addInterceptors(registry); - registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService())); - registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider())); + registry.addInterceptor(new ConversionServiceExposingInterceptor(mvcConversionService)); + registry.addInterceptor(new ResourceUrlProviderExposingInterceptor(mvcResourceUrlProvider)); this.interceptors = registry.getInterceptors(); } return this.interceptors.toArray(); @@ -441,7 +446,10 @@ protected void configureContentNegotiation(ContentNegotiationConfigurer configur */ @Bean @Nullable - public HandlerMapping viewControllerHandlerMapping() { + public HandlerMapping viewControllerHandlerMapping(PathMatcher mvcPathMatcher, + UrlPathHelper mvcUrlPathHelper, + FormattingConversionService mvcConversionService, + ResourceUrlProvider mvcResourceUrlProvider) { ViewControllerRegistry registry = new ViewControllerRegistry(this.applicationContext); addViewControllers(registry); @@ -449,9 +457,9 @@ public HandlerMapping viewControllerHandlerMapping() { if (handlerMapping == null) { return null; } - handlerMapping.setPathMatcher(mvcPathMatcher()); - handlerMapping.setUrlPathHelper(mvcUrlPathHelper()); - handlerMapping.setInterceptors(getInterceptors()); + handlerMapping.setPathMatcher(mvcPathMatcher); + handlerMapping.setUrlPathHelper(mvcUrlPathHelper); + handlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); handlerMapping.setCorsConfigurations(getCorsConfigurations()); return handlerMapping; } @@ -468,10 +476,11 @@ protected void addViewControllers(ViewControllerRegistry registry) { * paths to controller bean names. */ @Bean - public BeanNameUrlHandlerMapping beanNameHandlerMapping() { + public BeanNameUrlHandlerMapping beanNameHandlerMapping(FormattingConversionService mvcConversionService, + ResourceUrlProvider mvcResourceUrlProvider) { BeanNameUrlHandlerMapping mapping = new BeanNameUrlHandlerMapping(); mapping.setOrder(2); - mapping.setInterceptors(getInterceptors()); + mapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); mapping.setCorsConfigurations(getCorsConfigurations()); return mapping; } @@ -488,10 +497,11 @@ public BeanNameUrlHandlerMapping beanNameHandlerMapping() { * @since 5.2 */ @Bean - public RouterFunctionMapping routerFunctionMapping() { + public RouterFunctionMapping routerFunctionMapping(FormattingConversionService mvcConversionService, + ResourceUrlProvider mvcResourceUrlProvider) { RouterFunctionMapping mapping = new RouterFunctionMapping(); mapping.setOrder(3); - mapping.setInterceptors(getInterceptors()); + mapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); mapping.setCorsConfigurations(getCorsConfigurations()); mapping.setMessageConverters(getMessageConverters()); return mapping; @@ -504,21 +514,25 @@ public RouterFunctionMapping routerFunctionMapping() { */ @Bean @Nullable - public HandlerMapping resourceHandlerMapping() { + public HandlerMapping resourceHandlerMapping(UrlPathHelper mvcUrlPathHelper, + PathMatcher mvcPathMatcher, + ContentNegotiationManager mvcContentNegotiationManager, + FormattingConversionService mvcConversionService, + ResourceUrlProvider mvcResourceUrlProvider) { Assert.state(this.applicationContext != null, "No ApplicationContext set"); Assert.state(this.servletContext != null, "No ServletContext set"); ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext, - this.servletContext, mvcContentNegotiationManager(), mvcUrlPathHelper()); + this.servletContext, mvcContentNegotiationManager, mvcUrlPathHelper); addResourceHandlers(registry); AbstractHandlerMapping handlerMapping = registry.getHandlerMapping(); if (handlerMapping == null) { return null; } - handlerMapping.setPathMatcher(mvcPathMatcher()); - handlerMapping.setUrlPathHelper(mvcUrlPathHelper()); - handlerMapping.setInterceptors(getInterceptors()); + handlerMapping.setPathMatcher(mvcPathMatcher); + handlerMapping.setUrlPathHelper(mvcUrlPathHelper); + handlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider)); handlerMapping.setCorsConfigurations(getCorsConfigurations()); return handlerMapping; } @@ -580,11 +594,14 @@ protected void configureDefaultServletHandling(DefaultServletHandlerConfigurer c * */ @Bean - public RequestMappingHandlerAdapter requestMappingHandlerAdapter() { + public RequestMappingHandlerAdapter requestMappingHandlerAdapter( + ContentNegotiationManager mvcContentNegotiationManager, + FormattingConversionService mvcConversionService, + Validator mvcValidator) { RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter(); - adapter.setContentNegotiationManager(mvcContentNegotiationManager()); + adapter.setContentNegotiationManager(mvcContentNegotiationManager); adapter.setMessageConverters(getMessageConverters()); - adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer()); + adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(mvcConversionService, mvcValidator)); adapter.setCustomArgumentResolvers(getArgumentResolvers()); adapter.setCustomReturnValueHandlers(getReturnValueHandlers()); @@ -630,10 +647,12 @@ public HandlerFunctionAdapter handlerFunctionAdapter() { * Return the {@link ConfigurableWebBindingInitializer} to use for * initializing all {@link WebDataBinder} instances. */ - protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer() { + protected ConfigurableWebBindingInitializer getConfigurableWebBindingInitializer( + FormattingConversionService mvcConversionService, + Validator mvcValidator) { ConfigurableWebBindingInitializer initializer = new ConfigurableWebBindingInitializer(); - initializer.setConversionService(mvcConversionService()); - initializer.setValidator(mvcValidator()); + initializer.setConversionService(mvcConversionService); + initializer.setValidator(mvcValidator); MessageCodesResolver messageCodesResolver = getMessageCodesResolver(); if (messageCodesResolver != null) { initializer.setMessageCodesResolver(messageCodesResolver); @@ -879,9 +898,11 @@ else if (jsonbPresent) { * @since 4.0 */ @Bean - public CompositeUriComponentsContributor mvcUriComponentsContributor() { + public CompositeUriComponentsContributor mvcUriComponentsContributor( + FormattingConversionService mvcConversionService, + RequestMappingHandlerAdapter requestMappingHandlerAdapter) { return new CompositeUriComponentsContributor( - requestMappingHandlerAdapter().getArgumentResolvers(), mvcConversionService()); + requestMappingHandlerAdapter.getArgumentResolvers(), mvcConversionService); } /** @@ -911,11 +932,12 @@ public SimpleControllerHandlerAdapter simpleControllerHandlerAdapter() { * which allows for providing a list of resolvers. */ @Bean - public HandlerExceptionResolver handlerExceptionResolver() { + public HandlerExceptionResolver handlerExceptionResolver( + ContentNegotiationManager mvcContentNegotiationManager) { List exceptionResolvers = new ArrayList<>(); configureHandlerExceptionResolvers(exceptionResolvers); if (exceptionResolvers.isEmpty()) { - addDefaultHandlerExceptionResolvers(exceptionResolvers); + addDefaultHandlerExceptionResolvers(exceptionResolvers, mvcContentNegotiationManager); } extendHandlerExceptionResolvers(exceptionResolvers); HandlerExceptionResolverComposite composite = new HandlerExceptionResolverComposite(); @@ -958,9 +980,10 @@ protected void extendHandlerExceptionResolvers(List ex *

  • {@link DefaultHandlerExceptionResolver} for resolving known Spring exception types * */ - protected final void addDefaultHandlerExceptionResolvers(List exceptionResolvers) { + protected final void addDefaultHandlerExceptionResolvers(List exceptionResolvers, + ContentNegotiationManager mvcContentNegotiationManager) { ExceptionHandlerExceptionResolver exceptionHandlerResolver = createExceptionHandlerExceptionResolver(); - exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager()); + exceptionHandlerResolver.setContentNegotiationManager(mvcContentNegotiationManager); exceptionHandlerResolver.setMessageConverters(getMessageConverters()); exceptionHandlerResolver.setCustomArgumentResolvers(getArgumentResolvers()); exceptionHandlerResolver.setCustomReturnValueHandlers(getReturnValueHandlers()); @@ -1003,9 +1026,9 @@ protected ExceptionHandlerExceptionResolver createExceptionHandlerExceptionResol * @since 4.1 */ @Bean - public ViewResolver mvcViewResolver() { + public ViewResolver mvcViewResolver(ContentNegotiationManager mvcContentNegotiationManager) { ViewResolverRegistry registry = new ViewResolverRegistry( - mvcContentNegotiationManager(), this.applicationContext); + mvcContentNegotiationManager, this.applicationContext); configureViewResolvers(registry); if (registry.getViewResolvers().isEmpty() && this.applicationContext != null) { diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java index fe97abca84b8..bb15ba6afa28 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/config/annotation/DelegatingWebMvcConfigurationTests.java @@ -97,7 +97,9 @@ public void setUp() { @Test public void requestMappingHandlerAdapter() throws Exception { delegatingConfig.setConfigurers(Collections.singletonList(webMvcConfigurer)); - RequestMappingHandlerAdapter adapter = this.delegatingConfig.requestMappingHandlerAdapter(); + RequestMappingHandlerAdapter adapter = this.delegatingConfig.requestMappingHandlerAdapter( + this.delegatingConfig.mvcContentNegotiationManager(), this.delegatingConfig.mvcConversionService(), + this.delegatingConfig.mvcValidator()); ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer(); @@ -128,6 +130,7 @@ public void configureMessageConverters() { public void configureMessageConverters(List> converters) { converters.add(stringConverter); } + @Override public void extendMessageConverters(List> converters) { converters.add(0, customConverter); @@ -136,7 +139,9 @@ public void extendMessageConverters(List> converters) { delegatingConfig = new DelegatingWebMvcConfiguration(); delegatingConfig.setConfigurers(configurers); - RequestMappingHandlerAdapter adapter = delegatingConfig.requestMappingHandlerAdapter(); + RequestMappingHandlerAdapter adapter = delegatingConfig.requestMappingHandlerAdapter( + this.delegatingConfig.mvcContentNegotiationManager(), this.delegatingConfig.mvcConversionService(), + this.delegatingConfig.mvcValidator()); assertEquals("Only one custom converter should be registered", 2, adapter.getMessageConverters().size()); assertSame(customConverter, adapter.getMessageConverters().get(0)); assertSame(stringConverter, adapter.getMessageConverters().get(1)); @@ -165,7 +170,7 @@ public void getCustomMessageCodesResolver() { @Test public void handlerExceptionResolver() throws Exception { delegatingConfig.setConfigurers(Collections.singletonList(webMvcConfigurer)); - delegatingConfig.handlerExceptionResolver(); + delegatingConfig.handlerExceptionResolver(delegatingConfig.mvcContentNegotiationManager()); verify(webMvcConfigurer).configureMessageConverters(converters.capture()); verify(webMvcConfigurer).configureContentNegotiation(contentNegotiationConfigurer.capture()); @@ -190,7 +195,8 @@ public void configureHandlerExceptionResolvers(List ex delegatingConfig.setConfigurers(configurers); HandlerExceptionResolverComposite composite = - (HandlerExceptionResolverComposite) delegatingConfig.handlerExceptionResolver(); + (HandlerExceptionResolverComposite) delegatingConfig + .handlerExceptionResolver(delegatingConfig.mvcContentNegotiationManager()); assertEquals("Only one custom converter is expected", 1, composite.getExceptionResolvers().size()); } @@ -211,7 +217,9 @@ public void configurePathMatch(PathMatchConfigurer configurer) { }); delegatingConfig.setConfigurers(configurers); - RequestMappingHandlerMapping handlerMapping = delegatingConfig.requestMappingHandlerMapping(); + RequestMappingHandlerMapping handlerMapping = delegatingConfig.requestMappingHandlerMapping( + delegatingConfig.mvcContentNegotiationManager(), delegatingConfig.mvcConversionService(), + delegatingConfig.mvcResourceUrlProvider()); assertNotNull(handlerMapping); assertEquals("PathMatchConfigurer should configure RegisteredSuffixPatternMatch", true, handlerMapping.useRegisteredSuffixPatternMatch()); 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 71b6617efc0b..f037784ba68c 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 @@ -130,7 +130,9 @@ public void setUp() { @Test public void handlerMappings() throws Exception { - RequestMappingHandlerMapping rmHandlerMapping = this.config.requestMappingHandlerMapping(); + RequestMappingHandlerMapping rmHandlerMapping = this.config.requestMappingHandlerMapping( + this.config.mvcContentNegotiationManager(), + this.config.mvcConversionService(), this.config.mvcResourceUrlProvider()); rmHandlerMapping.setApplicationContext(this.context); rmHandlerMapping.afterPropertiesSet(); assertEquals(TestPathHelper.class, rmHandlerMapping.getUrlPathHelper().getClass()); @@ -152,7 +154,9 @@ public void handlerMappings() throws Exception { .getKey(); assertEquals(Collections.singleton("/api/user/{id}"), info.getPatternsCondition().getPatterns()); - AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) this.config.viewControllerHandlerMapping(); + AbstractHandlerMapping handlerMapping = (AbstractHandlerMapping) this.config.viewControllerHandlerMapping( + this.config.mvcPathMatcher(), this.config.mvcUrlPathHelper(), + this.config.mvcConversionService(), this.config.mvcResourceUrlProvider()); handlerMapping.setApplicationContext(this.context); assertNotNull(handlerMapping); assertEquals(1, handlerMapping.getOrder()); @@ -168,7 +172,10 @@ public void handlerMappings() throws Exception { assertNotNull(chain); assertNotNull(chain.getHandler()); - handlerMapping = (AbstractHandlerMapping) this.config.resourceHandlerMapping(); + handlerMapping = (AbstractHandlerMapping) this.config.resourceHandlerMapping( + this.config.mvcUrlPathHelper(), this.config.mvcPathMatcher(), + this.config.mvcContentNegotiationManager(), this.config.mvcConversionService(), + this.config.mvcResourceUrlProvider()); handlerMapping.setApplicationContext(this.context); assertNotNull(handlerMapping); assertEquals(Integer.MAX_VALUE - 1, handlerMapping.getOrder()); @@ -195,7 +202,9 @@ public void handlerMappings() throws Exception { @SuppressWarnings("unchecked") @Test public void requestMappingHandlerAdapter() throws Exception { - RequestMappingHandlerAdapter adapter = this.config.requestMappingHandlerAdapter(); + RequestMappingHandlerAdapter adapter = this.config.requestMappingHandlerAdapter( + this.config.mvcContentNegotiationManager(), this.config.mvcConversionService(), + this.config.mvcValidator()); // ConversionService String actual = this.config.mvcConversionService().convert(new TestBean(), String.class); @@ -215,11 +224,11 @@ public void requestMappingHandlerAdapter() throws Exception { // Custom argument resolvers and return value handlers List argResolvers = - (List) fieldAccessor.getPropertyValue("customArgumentResolvers"); + (List) fieldAccessor.getPropertyValue("customArgumentResolvers"); assertEquals(1, argResolvers.size()); List handlers = - (List) fieldAccessor.getPropertyValue("customReturnValueHandlers"); + (List) fieldAccessor.getPropertyValue("customReturnValueHandlers"); assertEquals(1, handlers.size()); // Async support options @@ -239,7 +248,9 @@ public void requestMappingHandlerAdapter() throws Exception { @Test public void webBindingInitializer() throws Exception { - RequestMappingHandlerAdapter adapter = this.config.requestMappingHandlerAdapter(); + RequestMappingHandlerAdapter adapter = this.config.requestMappingHandlerAdapter( + this.config.mvcContentNegotiationManager(), this.config.mvcConversionService(), + this.config.mvcValidator()); ConfigurableWebBindingInitializer initializer = (ConfigurableWebBindingInitializer) adapter.getWebBindingInitializer(); @@ -259,7 +270,9 @@ public void contentNegotiation() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo.json"); NativeWebRequest webRequest = new ServletWebRequest(request); - RequestMappingHandlerMapping mapping = this.config.requestMappingHandlerMapping(); + RequestMappingHandlerMapping mapping = this.config.requestMappingHandlerMapping( + this.config.mvcContentNegotiationManager(), this.config.mvcConversionService(), + this.config.mvcResourceUrlProvider()); ContentNegotiationManager manager = mapping.getContentNegotiationManager(); assertEquals(Collections.singletonList(APPLICATION_JSON), manager.resolveMediaTypes(webRequest)); @@ -278,7 +291,10 @@ public void contentNegotiation() throws Exception { assertEquals(Collections.singletonList(APPLICATION_JSON), manager.resolveMediaTypes(webRequest)); request.setRequestURI("/resources/foo.gif"); - SimpleUrlHandlerMapping handlerMapping = (SimpleUrlHandlerMapping) this.config.resourceHandlerMapping(); + SimpleUrlHandlerMapping handlerMapping = (SimpleUrlHandlerMapping) this.config.resourceHandlerMapping( + this.config.mvcUrlPathHelper(), this.config.mvcPathMatcher(), + this.config.mvcContentNegotiationManager(), this.config.mvcConversionService(), + this.config.mvcResourceUrlProvider()); handlerMapping.setApplicationContext(this.context); HandlerExecutionChain chain = handlerMapping.getHandler(request); assertNotNull(chain); @@ -290,7 +306,7 @@ public void contentNegotiation() throws Exception { @Test public void exceptionResolvers() throws Exception { List resolvers = ((HandlerExceptionResolverComposite) - this.config.handlerExceptionResolver()).getExceptionResolvers(); + this.config.handlerExceptionResolver(null)).getExceptionResolvers(); assertEquals(2, resolvers.size()); assertEquals(ResponseStatusExceptionResolver.class, resolvers.get(0).getClass()); @@ -300,7 +316,8 @@ public void exceptionResolvers() throws Exception { @SuppressWarnings("unchecked") @Test public void viewResolvers() throws Exception { - ViewResolverComposite viewResolver = (ViewResolverComposite) this.config.mvcViewResolver(); + ViewResolverComposite viewResolver = (ViewResolverComposite) this.config.mvcViewResolver( + this.config.mvcContentNegotiationManager()); assertEquals(Ordered.HIGHEST_PRECEDENCE, viewResolver.getOrder()); List viewResolvers = viewResolver.getViewResolvers(); @@ -310,12 +327,12 @@ public void viewResolvers() throws Exception { assertFalse((Boolean) accessor.getPropertyValue("useNotAcceptableStatusCode")); assertNotNull(accessor.getPropertyValue("contentNegotiationManager")); - List defaultViews = (List)accessor.getPropertyValue("defaultViews"); + List defaultViews = (List) accessor.getPropertyValue("defaultViews"); assertNotNull(defaultViews); assertEquals(1, defaultViews.size()); assertEquals(MappingJackson2JsonView.class, defaultViews.get(0).getClass()); - viewResolvers = (List)accessor.getPropertyValue("viewResolvers"); + viewResolvers = (List) accessor.getPropertyValue("viewResolvers"); assertNotNull(viewResolvers); assertEquals(1, viewResolvers.size()); assertEquals(InternalResourceViewResolver.class, viewResolvers.get(0).getClass()); @@ -376,6 +393,7 @@ public Validator getValidator() { public void validate(@Nullable Object target, Errors errors) { errors.reject("invalid"); } + @Override public boolean supports(Class clazz) { return true; @@ -391,8 +409,10 @@ public void configureContentNegotiation(ContentNegotiationConfigurer configurer) @Override public void configureAsyncSupport(AsyncSupportConfigurer configurer) { configurer.setDefaultTimeout(2500).setTaskExecutor(new ConcurrentTaskExecutor()) - .registerCallableInterceptors(new CallableProcessingInterceptor() { }) - .registerDeferredResultInterceptors(new DeferredResultProcessingInterceptor() {}); + .registerCallableInterceptors(new CallableProcessingInterceptor() { + }) + .registerDeferredResultInterceptors(new DeferredResultProcessingInterceptor() { + }); } @Override @@ -433,7 +453,7 @@ public MessageCodesResolver getMessageCodesResolver() { return new DefaultMessageCodesResolver() { @Override public String[] resolveMessageCodes(String errorCode, String objectName) { - return new String[] { "custom." + errorCode }; + return new String[] {"custom." + errorCode}; } }; } @@ -468,9 +488,11 @@ public void addCorsMappings(CorsRegistry registry) { } - private class TestPathHelper extends UrlPathHelper {} + private class TestPathHelper extends UrlPathHelper { + } - private class TestPathMatcher extends AntPathMatcher {} + private class TestPathMatcher extends AntPathMatcher { + } @RestController