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 dce95a0235e..17fdf02836a 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-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -28,10 +28,15 @@ import org.springframework.lang.Nullable; import org.springframework.util.AntPathMatcher; import org.springframework.util.PathMatcher; import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.servlet.DispatcherServlet; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; import org.springframework.web.servlet.handler.HandlerMappingIntrospector; +import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; +import org.springframework.web.servlet.support.SessionFlashMapManager; +import org.springframework.web.servlet.theme.FixedThemeResolver; +import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator; import org.springframework.web.util.UrlPathHelper; /** @@ -39,6 +44,7 @@ import org.springframework.web.util.UrlPathHelper; * * @author Rossen Stoyanchev * @author Brian Clozel + * @author Marten Deinum * @since 3.1 */ public abstract class MvcNamespaceUtils { @@ -66,6 +72,10 @@ public abstract class MvcNamespaceUtils { registerHttpRequestHandlerAdapter(parserContext, source); registerSimpleControllerHandlerAdapter(parserContext, source); registerHandlerMappingIntrospector(parserContext, source); + registerThemeResolver(parserContext, source); + registerLocaleResolver(parserContext, source); + registerFlashMapManager(parserContext, source); + registerViewNameTranslator(parserContext, source); } /** @@ -205,6 +215,62 @@ public abstract class MvcNamespaceUtils { } } + /** + * Registers an {@link FixedThemeResolver} under a well-known name + * unless already registered. + */ + private static void registerThemeResolver(ParserContext parserContext, @Nullable Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.THEME_RESOLVER_BEAN_NAME)) { + RootBeanDefinition beanDef = new RootBeanDefinition(FixedThemeResolver.class); + beanDef.setSource(source); + beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.THEME_RESOLVER_BEAN_NAME, beanDef); + parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.THEME_RESOLVER_BEAN_NAME)); + } + } + + /** + * Registers an {@link AcceptHeaderLocaleResolver} under a well-known name + * unless already registered. + */ + private static void registerLocaleResolver(ParserContext parserContext, @Nullable Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)) { + RootBeanDefinition beanDef = new RootBeanDefinition(AcceptHeaderLocaleResolver.class); + beanDef.setSource(source); + beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME, beanDef); + parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME)); + } + } + + /** + * Registers an {@link SessionFlashMapManager} under a well-known name + * unless already registered. + */ + private static void registerFlashMapManager(ParserContext parserContext, @Nullable Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME)) { + RootBeanDefinition beanDef = new RootBeanDefinition(SessionFlashMapManager.class); + beanDef.setSource(source); + beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME, beanDef); + parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME)); + } + } + + /** + * Registers an {@link DefaultRequestToViewNameTranslator} under a well-known name + * unless already registered. + */ + private static void registerViewNameTranslator(ParserContext parserContext, @Nullable Object source) { + if (!parserContext.getRegistry().containsBeanDefinition(DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME)) { + RootBeanDefinition beanDef = new RootBeanDefinition(DefaultRequestToViewNameTranslator.class); + beanDef.setSource(source); + beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + parserContext.getRegistry().registerBeanDefinition(DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, beanDef); + parserContext.registerComponent(new BeanComponentDefinition(beanDef, DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_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 89dddbb9669..c64fcc7ed8e 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 @@ -74,9 +74,13 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.method.support.CompositeUriComponentsContributor; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; +import org.springframework.web.servlet.FlashMapManager; import org.springframework.web.servlet.HandlerAdapter; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.RequestToViewNameTranslator; +import org.springframework.web.servlet.ThemeResolver; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.function.support.HandlerFunctionAdapter; import org.springframework.web.servlet.function.support.RouterFunctionMapping; @@ -85,6 +89,7 @@ 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.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.mvc.Controller; import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; @@ -97,6 +102,9 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.resource.ResourceUrlProvider; import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor; +import org.springframework.web.servlet.support.SessionFlashMapManager; +import org.springframework.web.servlet.theme.FixedThemeResolver; +import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.ViewResolverComposite; import org.springframework.web.util.UrlPathHelper; @@ -1099,6 +1107,26 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv return new HandlerMappingIntrospector(); } + @Bean + public LocaleResolver localeResolver() { + return new AcceptHeaderLocaleResolver(); + } + + @Bean + public ThemeResolver themeResolver() { + return new FixedThemeResolver(); + } + + @Bean + public FlashMapManager flashMapManager() { + return new SessionFlashMapManager(); + } + + @Bean + public RequestToViewNameTranslator viewNameTranslator() { + return new DefaultRequestToViewNameTranslator(); + } + private static final class NoOpValidator implements Validator { 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 fff66e500a4..ed22feb0621 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-2019 the original author or authors. + * Copyright 2002-2020 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. @@ -85,9 +85,13 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.support.CompositeUriComponentsContributor; import org.springframework.web.method.support.InvocableHandlerMethod; +import org.springframework.web.servlet.FlashMapManager; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.RequestToViewNameTranslator; +import org.springframework.web.servlet.ThemeResolver; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.handler.AbstractHandlerMapping; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; @@ -154,6 +158,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Sebastien Deleuze * @author Kazuki Shimizu * @author Sam Brannen + * @author Marten Deinum */ public class MvcNamespaceTests { @@ -221,6 +226,10 @@ public class MvcNamespaceTests { assertThat(appContext.getBean(ConversionService.class)).isNotNull(); assertThat(appContext.getBean(LocalValidatorFactoryBean.class)).isNotNull(); assertThat(appContext.getBean(Validator.class)).isNotNull(); + assertThat(appContext.getBean("themeResolver", ThemeResolver.class)).isNotNull(); + assertThat(appContext.getBean("localeResolver", LocaleResolver.class)).isNotNull(); + assertThat(appContext.getBean("flashMapManager", FlashMapManager.class)).isNotNull(); + assertThat(appContext.getBean("viewNameTranslator", RequestToViewNameTranslator.class)).isNotNull(); // default web binding initializer behavior test request = new MockHttpServletRequest("GET", "/"); 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 f4d1330ac32..f74629287e6 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 @@ -63,13 +63,18 @@ import org.springframework.web.method.support.CompositeUriComponentsContributor; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; +import org.springframework.web.servlet.FlashMapManager; import org.springframework.web.servlet.HandlerExceptionResolver; import org.springframework.web.servlet.HandlerExecutionChain; import org.springframework.web.servlet.HandlerMapping; +import org.springframework.web.servlet.LocaleResolver; +import org.springframework.web.servlet.RequestToViewNameTranslator; +import org.springframework.web.servlet.ThemeResolver; import org.springframework.web.servlet.ViewResolver; 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.i18n.AcceptHeaderLocaleResolver; import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.JsonViewRequestBodyAdvice; @@ -79,7 +84,10 @@ 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.servlet.support.SessionFlashMapManager; +import org.springframework.web.servlet.theme.FixedThemeResolver; import org.springframework.web.servlet.view.BeanNameViewResolver; +import org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.ViewResolverComposite; import org.springframework.web.testfixture.servlet.MockHttpServletRequest; @@ -90,6 +98,10 @@ import org.springframework.web.util.UrlPathHelper; import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; import static com.fasterxml.jackson.databind.MapperFeature.DEFAULT_VIEW_INCLUSION; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER_BEAN_NAME; +import static org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER_BEAN_NAME; +import static org.springframework.web.servlet.DispatcherServlet.REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME; +import static org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER_BEAN_NAME; /** * Integration tests for {@link WebMvcConfigurationSupport} (imported via @@ -99,6 +111,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Juergen Hoeller * @author Sebastien Deleuze * @author Sam Brannen + * @author Marten Deinum */ public class WebMvcConfigurationSupportTests { @@ -310,6 +323,44 @@ public class WebMvcConfigurationSupportTests { assertThat(pathMatcher.getClass()).isEqualTo(AntPathMatcher.class); } + @Test + public void defaultLocaleResolverConfiguration() { + ApplicationContext context = initContext(WebConfig.class); + LocaleResolver localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class); + + assertThat(localeResolver).isNotNull(); + assertThat(localeResolver).isInstanceOf(AcceptHeaderLocaleResolver.class); + } + + @Test + public void defaultThemeResolverfiguration() { + ApplicationContext context = initContext(WebConfig.class); + ThemeResolver themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class); + + assertThat(themeResolver).isNotNull(); + assertThat(themeResolver).isInstanceOf(FixedThemeResolver.class); + } + + @Test + public void defaultFlashMapManagerConfiguration() { + ApplicationContext context = initContext(WebConfig.class); + FlashMapManager flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class); + + assertThat(flashMapManager).isNotNull(); + assertThat(flashMapManager).isInstanceOf(SessionFlashMapManager.class); + } + + @Test + public void defaultRequestToViewNameConfiguration() throws Exception { + ApplicationContext context = initContext(WebConfig.class); + RequestToViewNameTranslator requestToViewNameTranslator; + requestToViewNameTranslator = context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, + RequestToViewNameTranslator.class); + + assertThat(requestToViewNameTranslator).isNotNull(); + assertThat(requestToViewNameTranslator).isInstanceOf(DefaultRequestToViewNameTranslator.class); + } + private ApplicationContext initContext(Class... configClasses) { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.setServletContext(new MockServletContext());