From c024dc836a486748a7a8e43db72cea00a46ebc32 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 28 Jun 2016 16:16:34 +0200 Subject: [PATCH] Support Spring Mobile for all template engines Previously, Spring Mobile was only supported for Thymeleaf and JSPs. This commit improves the auto-configuration to also provide device delegating support for Freemarker, Groovy Templates and Mustache. Closes gh-5140 --- ...legatingViewResolverAutoConfiguration.java | 162 +++++++------- .../DeviceDelegatingViewResolverFactory.java | 85 +++++++ ...ingViewResolverAutoConfigurationTests.java | 211 ++++++++---------- 3 files changed, 251 insertions(+), 207 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverFactory.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfiguration.java index 12615b7576d..e70f5fd8b6c 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfiguration.java @@ -16,27 +16,27 @@ package org.springframework.boot.autoconfigure.mobile; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.thymeleaf.spring4.view.ThymeleafViewResolver; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; +import org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration; +import org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration; +import org.springframework.boot.autoconfigure.mustache.web.MustacheViewResolver; import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.Ordered; import org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver; -import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; +import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Mobile's @@ -45,102 +45,96 @@ import org.springframework.web.servlet.view.InternalResourceViewResolver; * {@link InternalResourceViewResolver} is used as a fallback. * * @author Roy Clarkson + * @author Stephane Nicoll * @since 1.1.0 */ @Configuration @ConditionalOnWebApplication @ConditionalOnClass(LiteDeviceDelegatingViewResolver.class) -@AutoConfigureAfter({ WebMvcAutoConfiguration.class, ThymeleafAutoConfiguration.class }) +@ConditionalOnProperty(prefix = "spring.mobile.devicedelegatingviewresolver", name = "enabled", havingValue = "true") +@EnableConfigurationProperties(DeviceDelegatingViewResolverProperties.class) +@AutoConfigureAfter({WebMvcAutoConfiguration.class, FreeMarkerAutoConfiguration.class, + GroovyTemplateAutoConfiguration.class, MustacheAutoConfiguration.class, + ThymeleafAutoConfiguration.class}) public class DeviceDelegatingViewResolverAutoConfiguration { - private static final Log logger = LogFactory - .getLog(DeviceDelegatingViewResolverAutoConfiguration.class); - - private static abstract class AbstractDelegateConfiguration { - - @Autowired - private DeviceDelegatingViewResolverProperties viewResolverProperties; - - protected LiteDeviceDelegatingViewResolver getConfiguredViewResolver( - ViewResolver delegate, int delegateOrder) { - LiteDeviceDelegatingViewResolver resolver = new LiteDeviceDelegatingViewResolver( - delegate); - resolver.setEnableFallback(this.viewResolverProperties.isEnableFallback()); - resolver.setNormalPrefix(this.viewResolverProperties.getNormalPrefix()); - resolver.setNormalSuffix(this.viewResolverProperties.getNormalSuffix()); - resolver.setMobilePrefix(this.viewResolverProperties.getMobilePrefix()); - resolver.setMobileSuffix(this.viewResolverProperties.getMobileSuffix()); - resolver.setTabletPrefix(this.viewResolverProperties.getTabletPrefix()); - resolver.setTabletSuffix(this.viewResolverProperties.getTabletSuffix()); - resolver.setOrder(getAdjustedOrder(delegateOrder)); - return resolver; - } + @Configuration + protected static class LiteDeviceDelegatingViewResolverFactoryConfiguration { - private int getAdjustedOrder(int order) { - if (order == Ordered.HIGHEST_PRECEDENCE) { - return Ordered.HIGHEST_PRECEDENCE; - } - // The view resolver must be ordered higher than the delegate view - // resolver, otherwise the view names will not be adjusted - return order - 1; + @Bean + public DeviceDelegatingViewResolverFactory deviceDelegatingViewResolverFactory( + DeviceDelegatingViewResolverProperties properties) { + return new DeviceDelegatingViewResolverFactory(properties); } } @Configuration - @EnableConfigurationProperties(DeviceDelegatingViewResolverProperties.class) - @ConditionalOnMissingBean(name = "deviceDelegatingViewResolver") - @ConditionalOnProperty(prefix = "spring.mobile.devicedelegatingviewresolver", name = "enabled", havingValue = "true", matchIfMissing = false) - protected static class DeviceDelegatingViewResolverConfiguration { - - @Configuration - @ConditionalOnBean(name = "thymeleafViewResolver") - protected static class ThymeleafViewResolverViewResolverDelegateConfiguration - extends AbstractDelegateConfiguration { - - private final ThymeleafViewResolver viewResolver; - - protected ThymeleafViewResolverViewResolverDelegateConfiguration( - ThymeleafViewResolver viewResolver) { - this.viewResolver = viewResolver; - } - - @Bean - public LiteDeviceDelegatingViewResolver deviceDelegatingViewResolver() { - if (logger.isDebugEnabled()) { - logger.debug("LiteDeviceDelegatingViewResolver delegates to " - + "ThymeleafViewResolver"); - } - return getConfiguredViewResolver(this.viewResolver, - this.viewResolver.getOrder()); - } + @ConditionalOnClass(FreeMarkerViewResolver.class) + protected static class DeviceDelegatingFreemarkerViewResolverConfiguration { + + @Bean + @ConditionalOnBean(FreeMarkerViewResolver.class) + public LiteDeviceDelegatingViewResolver deviceDelegatingFreemarkerViewResolver( + DeviceDelegatingViewResolverFactory factory, + FreeMarkerViewResolver viewResolver) { + return factory.createViewResolver(viewResolver); + } + + } + @Configuration + @ConditionalOnClass(GroovyMarkupViewResolver.class) + protected static class DeviceDelegatingGroovyMarkupViewResolverConfiguration { + + @Bean + @ConditionalOnBean(GroovyMarkupViewResolver.class) + public LiteDeviceDelegatingViewResolver deviceDelegatingGroovyMarkupViewResolver( + DeviceDelegatingViewResolverFactory factory, + GroovyMarkupViewResolver viewResolver) { + return factory.createViewResolver(viewResolver); } - @Configuration - @EnableConfigurationProperties(DeviceDelegatingViewResolverProperties.class) - @ConditionalOnMissingBean(name = "thymeleafViewResolver") + } + + @Configuration + @ConditionalOnClass(InternalResourceViewResolver.class) + protected static class DeviceDelegatingJspViewResolverConfiguration { + + @Bean @ConditionalOnBean(InternalResourceViewResolver.class) - protected static class InternalResourceViewResolverDelegateConfiguration - extends AbstractDelegateConfiguration { - - private final InternalResourceViewResolver viewResolver; - - protected InternalResourceViewResolverDelegateConfiguration( - InternalResourceViewResolver viewResolver) { - this.viewResolver = viewResolver; - } - - @Bean - public LiteDeviceDelegatingViewResolver deviceDelegatingViewResolver() { - if (logger.isDebugEnabled()) { - logger.debug("LiteDeviceDelegatingViewResolver delegates to " - + "InternalResourceViewResolver"); - } - return getConfiguredViewResolver(this.viewResolver, - this.viewResolver.getOrder()); - } + public LiteDeviceDelegatingViewResolver deviceDelegatingJspViewResolver( + DeviceDelegatingViewResolverFactory factory, + InternalResourceViewResolver viewResolver) { + return factory.createViewResolver(viewResolver); + } + + } + @Configuration + @ConditionalOnClass(MustacheViewResolver.class) + protected static class DeviceDelegatingMustacheViewResolverConfiguration { + + @Bean + @ConditionalOnBean(MustacheViewResolver.class) + public LiteDeviceDelegatingViewResolver deviceDelegatingMustacheViewResolver( + DeviceDelegatingViewResolverFactory factory, + MustacheViewResolver viewResolver) { + return factory.createViewResolver(viewResolver); + } + + } + + @Configuration + @ConditionalOnClass(ThymeleafViewResolver.class) + protected static class DeviceDelegatingThymeleafViewResolverConfiguration { + + @Bean + @ConditionalOnBean(ThymeleafViewResolver.class) + public LiteDeviceDelegatingViewResolver deviceDelegatingThymeleafViewResolver( + DeviceDelegatingViewResolverFactory factory, + ThymeleafViewResolver viewResolver) { + return factory.createViewResolver(viewResolver); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverFactory.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverFactory.java new file mode 100644 index 00000000000..b0ba4255925 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverFactory.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2016 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.mobile; + +import org.springframework.core.Ordered; +import org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver; +import org.springframework.web.servlet.ViewResolver; + +/** + * A factory for {@link LiteDeviceDelegatingViewResolver} that applies customizations + * of {@link DeviceDelegatingViewResolverProperties}. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +public class DeviceDelegatingViewResolverFactory { + + private final DeviceDelegatingViewResolverProperties properties; + + public DeviceDelegatingViewResolverFactory(DeviceDelegatingViewResolverProperties properties) { + this.properties = properties; + } + + /** + * Create a {@link LiteDeviceDelegatingViewResolver} delegating to the specified + * {@link ViewResolver}. + * @param delegate the view resolver to delegate to + * @param delegatingOrder the order of the {@link LiteDeviceDelegatingViewResolver} + * @return a {@link LiteDeviceDelegatingViewResolver} handling the specified resolver + */ + public LiteDeviceDelegatingViewResolver createViewResolver( + ViewResolver delegate, int delegatingOrder) { + LiteDeviceDelegatingViewResolver resolver = new LiteDeviceDelegatingViewResolver( + delegate); + resolver.setEnableFallback(this.properties.isEnableFallback()); + resolver.setNormalPrefix(this.properties.getNormalPrefix()); + resolver.setNormalSuffix(this.properties.getNormalSuffix()); + resolver.setMobilePrefix(this.properties.getMobilePrefix()); + resolver.setMobileSuffix(this.properties.getMobileSuffix()); + resolver.setTabletPrefix(this.properties.getTabletPrefix()); + resolver.setTabletSuffix(this.properties.getTabletSuffix()); + resolver.setOrder(delegatingOrder); + return resolver; + } + + /** + * Create a {@link LiteDeviceDelegatingViewResolver} delegating to the specified + * {@link ViewResolver} and computing a sensible order for it. The specified + * {@link ViewResolver} should implement {@link Ordered}, consider using + * {@link #createViewResolver(ViewResolver, int)} if that's not the case. + * @param delegate the view resolver to delegate to + * @return a {@link LiteDeviceDelegatingViewResolver} handling the specified resolver + */ + public LiteDeviceDelegatingViewResolver createViewResolver(ViewResolver delegate) { + if (!(delegate instanceof Ordered)) { + throw new IllegalStateException("ViewResolver " + delegate + "should implement " + Ordered.class.getName()); + } + int delegateOrder = ((Ordered) delegate).getOrder(); + return createViewResolver(delegate, adjustOrder(delegateOrder)); + } + + private int adjustOrder(int order) { + if (order == Ordered.HIGHEST_PRECEDENCE) { + return Ordered.HIGHEST_PRECEDENCE; + } + // The view resolver must be ordered higher than the delegate view + // resolver, otherwise the view names will not be adjusted + return order - 1; + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfigurationTests.java index db80c9e27c5..157dd9a001b 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mobile/DeviceDelegatingViewResolverAutoConfigurationTests.java @@ -16,28 +16,36 @@ package org.springframework.boot.autoconfigure.mobile; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.thymeleaf.spring4.view.ThymeleafViewResolver; import org.springframework.beans.DirectFieldAccessor; import org.springframework.beans.PropertyAccessor; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.mobile.DeviceDelegatingViewResolverAutoConfiguration.DeviceDelegatingViewResolverConfiguration; +import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; +import org.springframework.boot.autoconfigure.groovy.template.GroovyTemplateAutoConfiguration; +import org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration; +import org.springframework.boot.autoconfigure.mustache.web.MustacheViewResolver; import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; import org.springframework.boot.autoconfigure.web.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; -import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext; -import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor; -import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory; -import org.springframework.boot.context.embedded.MockEmbeddedServletContainerFactory; import org.springframework.boot.test.util.EnvironmentTestUtils; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.mobile.device.view.AbstractDeviceDelegatingViewResolver; +import org.springframework.core.Ordered; import org.springframework.mobile.device.view.LiteDeviceDelegatingViewResolver; +import org.springframework.mock.web.MockServletContext; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.view.InternalResourceViewResolver; +import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; +import org.springframework.web.servlet.view.groovy.GroovyMarkupViewResolver; import static org.assertj.core.api.Assertions.assertThat; @@ -49,9 +57,10 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class DeviceDelegatingViewResolverAutoConfigurationTests { - private static final MockEmbeddedServletContainerFactory containerFactory = new MockEmbeddedServletContainerFactory(); + @Rule + public final ExpectedException thrown = ExpectedException.none(); - private AnnotationConfigEmbeddedWebApplicationContext context; + private AnnotationConfigWebApplicationContext context; @After public void close() { @@ -60,123 +69,82 @@ public class DeviceDelegatingViewResolverAutoConfigurationTests { } } - @Test(expected = NoSuchBeanDefinitionException.class) + @Test public void deviceDelegatingViewResolverDefaultDisabled() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - this.context.register(Config.class, - DeviceDelegatingViewResolverConfiguration.class); - this.context.refresh(); - this.context.getBean("deviceDelegatingViewResolver", - AbstractDeviceDelegatingViewResolver.class); + load(); + this.thrown.expect(NoSuchBeanDefinitionException.class); + this.context.getBean(LiteDeviceDelegatingViewResolver.class); } @Test - public void deviceDelegatingInternalResourceViewResolverEnabled() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.mobile.devicedelegatingviewresolver.enabled:true"); - this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - DeviceDelegatingViewResolverConfiguration.class); - this.context.refresh(); + public void deviceDelegatingJspResourceViewResolver() throws Exception { + load("spring.mobile.devicedelegatingviewresolver.enabled:true"); + assertThat(this.context.getBeansOfType(LiteDeviceDelegatingViewResolver.class)).hasSize(1); InternalResourceViewResolver internalResourceViewResolver = this.context .getBean(InternalResourceViewResolver.class); - AbstractDeviceDelegatingViewResolver deviceDelegatingViewResolver = this.context - .getBean("deviceDelegatingViewResolver", - AbstractDeviceDelegatingViewResolver.class); - assertThat(internalResourceViewResolver).isNotNull(); - assertThat(deviceDelegatingViewResolver).isNotNull(); - assertThat(deviceDelegatingViewResolver.getViewResolver()) - .isInstanceOf(InternalResourceViewResolver.class); - try { - this.context.getBean(ThymeleafViewResolver.class); - } - catch (NoSuchBeanDefinitionException ex) { - // expected. ThymeleafViewResolver shouldn't be defined. - } - assertThat(deviceDelegatingViewResolver.getOrder()) - .isEqualTo(internalResourceViewResolver.getOrder() - 1); + assertLiteDeviceDelegatingViewResolver(internalResourceViewResolver, + "deviceDelegatingJspViewResolver"); } - @Test(expected = NoSuchBeanDefinitionException.class) - public void deviceDelegatingInternalResourceViewResolverDisabled() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.mobile.devicedelegatingviewresolver.enabled:false"); - this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - DeviceDelegatingViewResolverConfiguration.class); - this.context.refresh(); - assertThat(this.context.getBean(InternalResourceViewResolver.class)).isNotNull(); - try { - this.context.getBean(ThymeleafViewResolver.class); - } - catch (NoSuchBeanDefinitionException ex) { - // expected. ThymeleafViewResolver shouldn't be defined. - } - this.context.getBean("deviceDelegatingViewResolver", - AbstractDeviceDelegatingViewResolver.class); + @Test + public void deviceDelegatingFreemarkerViewResolver() throws Exception { + load(Collections.>singletonList(FreeMarkerAutoConfiguration.class), + "spring.mobile.devicedelegatingviewresolver.enabled:true"); + assertThat(this.context.getBeansOfType(LiteDeviceDelegatingViewResolver.class)).hasSize(2); + assertLiteDeviceDelegatingViewResolver(this.context.getBean(FreeMarkerViewResolver.class), + "deviceDelegatingFreemarkerViewResolver"); } @Test - public void deviceDelegatingThymeleafViewResolverEnabled() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, + public void deviceDelegatingGroovyMarkupViewResolver() throws Exception { + load(Collections.>singletonList(GroovyTemplateAutoConfiguration.class), "spring.mobile.devicedelegatingviewresolver.enabled:true"); - this.context.register(Config.class, WebMvcAutoConfiguration.class, - ThymeleafAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - DeviceDelegatingViewResolverConfiguration.class); - this.context.refresh(); - ThymeleafViewResolver thymeleafViewResolver = this.context - .getBean(ThymeleafViewResolver.class); - AbstractDeviceDelegatingViewResolver deviceDelegatingViewResolver = this.context - .getBean("deviceDelegatingViewResolver", - AbstractDeviceDelegatingViewResolver.class); - assertThat(thymeleafViewResolver).isNotNull(); - assertThat(deviceDelegatingViewResolver).isNotNull(); + assertThat(this.context.getBeansOfType(LiteDeviceDelegatingViewResolver.class)).hasSize(2); + assertLiteDeviceDelegatingViewResolver(this.context.getBean(GroovyMarkupViewResolver.class), + "deviceDelegatingGroovyMarkupViewResolver"); + } + + @Test + public void deviceDelegatingMustacheViewResolver() throws Exception { + load(Collections.>singletonList(MustacheAutoConfiguration.class), + "spring.mobile.devicedelegatingviewresolver.enabled:true"); + assertThat(this.context.getBeansOfType(LiteDeviceDelegatingViewResolver.class)).hasSize(2); + assertLiteDeviceDelegatingViewResolver(this.context.getBean(MustacheViewResolver.class), + "deviceDelegatingMustacheViewResolver"); + } + + @Test + public void deviceDelegatingThymeleafViewResolver() throws Exception { + load(Collections.>singletonList(ThymeleafAutoConfiguration.class), + "spring.mobile.devicedelegatingviewresolver.enabled:true"); + assertThat(this.context.getBeansOfType(LiteDeviceDelegatingViewResolver.class)).hasSize(2); + assertLiteDeviceDelegatingViewResolver(this.context.getBean(ThymeleafViewResolver.class), + "deviceDelegatingThymeleafViewResolver"); + } + + public void assertLiteDeviceDelegatingViewResolver(ViewResolver delegate, String delegatingBeanName) { + LiteDeviceDelegatingViewResolver deviceDelegatingViewResolver = this.context + .getBean(delegatingBeanName, LiteDeviceDelegatingViewResolver.class); assertThat(deviceDelegatingViewResolver.getViewResolver()) - .isInstanceOf(ThymeleafViewResolver.class); - assertThat(this.context.getBean(InternalResourceViewResolver.class)).isNotNull(); - assertThat(this.context.getBean(ThymeleafViewResolver.class)).isNotNull(); + .isSameAs(delegate); assertThat(deviceDelegatingViewResolver.getOrder()) - .isEqualTo(thymeleafViewResolver.getOrder() - 1); + .isEqualTo(((Ordered) delegate).getOrder() - 1); } - @Test(expected = NoSuchBeanDefinitionException.class) - public void deviceDelegatingThymeleafViewResolverDisabled() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, + @Test + public void deviceDelegatingViewResolverDisabled() throws Exception { + load(Arrays.asList(FreeMarkerAutoConfiguration.class, GroovyTemplateAutoConfiguration.class, + MustacheAutoConfiguration.class, ThymeleafAutoConfiguration.class), "spring.mobile.devicedelegatingviewresolver.enabled:false"); - this.context.register(Config.class, WebMvcAutoConfiguration.class, - ThymeleafAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - DeviceDelegatingViewResolverConfiguration.class); - this.context.refresh(); - assertThat(this.context.getBean(InternalResourceViewResolver.class)).isNotNull(); - assertThat(this.context.getBean(ThymeleafViewResolver.class)).isNotNull(); - this.context.getBean("deviceDelegatingViewResolver", - AbstractDeviceDelegatingViewResolver.class); + assertThat(this.context.getBeansOfType(LiteDeviceDelegatingViewResolver.class)).hasSize(0); } @Test public void defaultPropertyValues() throws Exception { - this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, - "spring.mobile.devicedelegatingviewresolver.enabled:true"); - this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - DeviceDelegatingViewResolverConfiguration.class); - this.context.refresh(); + load("spring.mobile.devicedelegatingviewresolver.enabled:true"); LiteDeviceDelegatingViewResolver liteDeviceDelegatingViewResolver = this.context - .getBean("deviceDelegatingViewResolver", + .getBean("deviceDelegatingJspViewResolver", LiteDeviceDelegatingViewResolver.class); - DirectFieldAccessor accessor = new DirectFieldAccessor( liteDeviceDelegatingViewResolver); assertThat(accessor.getPropertyValue("enableFallback")).isEqualTo(Boolean.FALSE); @@ -246,32 +214,29 @@ public class DeviceDelegatingViewResolverAutoConfigurationTests { private PropertyAccessor getLiteDeviceDelegatingViewResolverAccessor( String... configuration) { - this.context = new AnnotationConfigEmbeddedWebApplicationContext(); - EnvironmentTestUtils.addEnvironment(this.context, configuration); - this.context.register(Config.class, WebMvcAutoConfiguration.class, - HttpMessageConvertersAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class, - DeviceDelegatingViewResolverConfiguration.class); - this.context.refresh(); + load(configuration); LiteDeviceDelegatingViewResolver liteDeviceDelegatingViewResolver = this.context - .getBean("deviceDelegatingViewResolver", + .getBean("deviceDelegatingJspViewResolver", LiteDeviceDelegatingViewResolver.class); return new DirectFieldAccessor(liteDeviceDelegatingViewResolver); } - @Configuration - protected static class Config { - - @Bean - public EmbeddedServletContainerFactory containerFactory() { - return containerFactory; - } + public void load(String... environment) { + load(null, environment); + } - @Bean - public EmbeddedServletContainerCustomizerBeanPostProcessor embeddedServletContainerCustomizerBeanPostProcessor() { - return new EmbeddedServletContainerCustomizerBeanPostProcessor(); + public void load(List> config, String... environment) { + this.context = new AnnotationConfigWebApplicationContext(); + this.context.setServletContext(new MockServletContext()); + if (config != null) { + this.context.register(config.toArray(new Class[config.size()])); } - + this.context.register(WebMvcAutoConfiguration.class, + HttpMessageConvertersAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class, + DeviceDelegatingViewResolverAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.context, environment); + this.context.refresh(); } }