diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/AbstractFreeMarkerConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/AbstractFreeMarkerConfiguration.java new file mode 100644 index 00000000000..d824b3de4e7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/AbstractFreeMarkerConfiguration.java @@ -0,0 +1,43 @@ +/* + * Copyright 2012-2017 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.freemarker; + +import java.util.Properties; + +import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory; + +class AbstractFreeMarkerConfiguration { + + private final FreeMarkerProperties properties; + + protected AbstractFreeMarkerConfiguration(FreeMarkerProperties properties) { + this.properties = properties; + } + + protected FreeMarkerProperties getProperties() { + return this.properties; + } + + protected void applyProperties(FreeMarkerConfigurationFactory factory) { + factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath()); + factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess()); + factory.setDefaultEncoding(this.properties.getCharsetName()); + Properties settings = new Properties(); + settings.putAll(this.properties.getSettings()); + factory.setFreemarkerSettings(settings); + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java index 4997dbb936a..afc6c558cc0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java @@ -18,36 +18,24 @@ package org.springframework.boot.autoconfigure.freemarker; import java.util.ArrayList; import java.util.List; -import java.util.Properties; import javax.annotation.PostConstruct; -import javax.servlet.Servlet; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -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.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.template.TemplateLocation; -import org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain; -import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory; import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean; -import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; -import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig; -import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; -import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; /** * {@link EnableAutoConfiguration Auto-configuration} for FreeMarker. @@ -58,10 +46,10 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; * @since 1.1.0 */ @Configuration -@ConditionalOnClass({ freemarker.template.Configuration.class, - FreeMarkerConfigurationFactory.class }) -@AutoConfigureAfter(WebMvcAutoConfiguration.class) +@ConditionalOnClass({freemarker.template.Configuration.class, + FreeMarkerConfigurationFactory.class}) @EnableConfigurationProperties(FreeMarkerProperties.class) +@Import({FreeMarkerServletWebConfiguration.class, FreeMarkerReactiveWebConfiguration.class}) public class FreeMarkerAutoConfiguration { private static final Log logger = LogFactory @@ -99,25 +87,13 @@ public class FreeMarkerAutoConfiguration { } } - protected static class FreeMarkerConfiguration { - - @Autowired - protected FreeMarkerProperties properties; - - protected void applyProperties(FreeMarkerConfigurationFactory factory) { - factory.setTemplateLoaderPaths(this.properties.getTemplateLoaderPath()); - factory.setPreferFileSystemAccess(this.properties.isPreferFileSystemAccess()); - factory.setDefaultEncoding(this.properties.getCharsetName()); - Properties settings = new Properties(); - settings.putAll(this.properties.getSettings()); - factory.setFreemarkerSettings(settings); - } - - } - @Configuration @ConditionalOnNotWebApplication - public static class FreeMarkerNonWebConfiguration extends FreeMarkerConfiguration { + public static class FreeMarkerNonWebConfiguration extends AbstractFreeMarkerConfiguration { + + public FreeMarkerNonWebConfiguration(FreeMarkerProperties properties) { + super(properties); + } @Bean @ConditionalOnMissingBean @@ -129,41 +105,4 @@ public class FreeMarkerAutoConfiguration { } - @Configuration - @ConditionalOnClass({ Servlet.class, FreeMarkerConfigurer.class }) - @ConditionalOnWebApplication(type = Type.SERVLET) - public static class FreeMarkerWebConfiguration extends FreeMarkerConfiguration { - - @Bean - @ConditionalOnMissingBean(FreeMarkerConfig.class) - public FreeMarkerConfigurer freeMarkerConfigurer() { - FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); - applyProperties(configurer); - return configurer; - } - - @Bean - public freemarker.template.Configuration freeMarkerConfiguration( - FreeMarkerConfig configurer) { - return configurer.getConfiguration(); - } - - @Bean - @ConditionalOnMissingBean(name = "freeMarkerViewResolver") - @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true) - public FreeMarkerViewResolver freeMarkerViewResolver() { - FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); - this.properties.applyToViewResolver(resolver); - return resolver; - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnEnabledResourceChain - public ResourceUrlEncodingFilter resourceUrlEncodingFilter() { - return new ResourceUrlEncodingFilter(); - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerReactiveWebConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerReactiveWebConfiguration.java new file mode 100644 index 00000000000..f63316aa8df --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerReactiveWebConfiguration.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2017 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.freemarker; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +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.web.reactive.WebFluxAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfig; +import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer; +import org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver; + +@Configuration +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) +@AutoConfigureAfter(WebFluxAutoConfiguration.class) +class FreeMarkerReactiveWebConfiguration extends AbstractFreeMarkerConfiguration { + + FreeMarkerReactiveWebConfiguration(FreeMarkerProperties properties) { + super(properties); + } + + @Bean + @ConditionalOnMissingBean(FreeMarkerConfig.class) + public FreeMarkerConfigurer freeMarkerConfigurer() { + FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); + applyProperties(configurer); + return configurer; + } + + @Bean + public freemarker.template.Configuration freeMarkerConfiguration( + FreeMarkerConfig configurer) { + return configurer.getConfiguration(); + } + + @Bean + @ConditionalOnMissingBean(name = "freeMarkerViewResolver") + @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true) + public FreeMarkerViewResolver freeMarkerViewResolver() { + FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); + resolver.setPrefix(getProperties().getPrefix()); + resolver.setSuffix(getProperties().getSuffix()); + resolver.setRequestContextAttribute(getProperties().getRequestContextAttribute()); + resolver.setViewNames(getProperties().getViewNames()); + return resolver; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerServletWebConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerServletWebConfiguration.java new file mode 100644 index 00000000000..988b2d174f4 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerServletWebConfiguration.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2017 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.freemarker; + +import javax.servlet.Servlet; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +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.web.ConditionalOnEnabledResourceChain; +import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; +import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; + +@Configuration +@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) +@ConditionalOnClass({Servlet.class, FreeMarkerConfigurer.class}) +@AutoConfigureAfter(WebMvcAutoConfiguration.class) +class FreeMarkerServletWebConfiguration extends AbstractFreeMarkerConfiguration { + + protected FreeMarkerServletWebConfiguration(FreeMarkerProperties properties) { + super(properties); + } + + @Bean + @ConditionalOnMissingBean(FreeMarkerConfig.class) + public FreeMarkerConfigurer freeMarkerConfigurer() { + FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); + applyProperties(configurer); + return configurer; + } + + @Bean + public freemarker.template.Configuration freeMarkerConfiguration( + FreeMarkerConfig configurer) { + return configurer.getConfiguration(); + } + + @Bean + @ConditionalOnMissingBean(name = "freeMarkerViewResolver") + @ConditionalOnProperty(name = "spring.freemarker.enabled", matchIfMissing = true) + public FreeMarkerViewResolver freeMarkerViewResolver() { + FreeMarkerViewResolver resolver = new FreeMarkerViewResolver(); + getProperties().applyToMvcViewResolver(resolver); + return resolver; + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnEnabledResourceChain + public ResourceUrlEncodingFilter resourceUrlEncodingFilter() { + return new ResourceUrlEncodingFilter(); + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java index 0a90402e465..9368d7d11cf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java @@ -153,7 +153,7 @@ public class GroovyTemplateAutoConfiguration { @ConditionalOnMissingBean(name = "groovyMarkupViewResolver") public GroovyMarkupViewResolver groovyMarkupViewResolver() { GroovyMarkupViewResolver resolver = new GroovyMarkupViewResolver(); - this.properties.applyToViewResolver(resolver); + this.properties.applyToMvcViewResolver(resolver); return resolver; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheServletWebConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheServletWebConfiguration.java index b3a41d0a9bc..2f0dae85da5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheServletWebConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/mustache/MustacheServletWebConfiguration.java @@ -40,7 +40,7 @@ class MustacheServletWebConfiguration { @ConditionalOnMissingBean(MustacheViewResolver.class) public MustacheViewResolver mustacheViewResolver(Compiler mustacheCompiler) { MustacheViewResolver resolver = new MustacheViewResolver(mustacheCompiler); - this.mustache.applyToViewResolver(resolver); + this.mustache.applyToMvcViewResolver(resolver); resolver.setCharset(this.mustache.getCharsetName()); resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 10); return resolver; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/AbstractTemplateViewResolverProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/AbstractTemplateViewResolverProperties.java index e2f700ccb73..a0abf2f432e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/AbstractTemplateViewResolverProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/AbstractTemplateViewResolverProperties.java @@ -152,7 +152,7 @@ public abstract class AbstractTemplateViewResolverProperties * can be used in a non-web application. * @param viewResolver the resolver to apply the properties to. */ - public void applyToViewResolver(Object viewResolver) { + public void applyToMvcViewResolver(Object viewResolver) { Assert.isInstanceOf(AbstractTemplateViewResolver.class, viewResolver, "ViewResolver is not an instance of AbstractTemplateViewResolver :" + viewResolver); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationReactiveIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationReactiveIntegrationTests.java new file mode 100644 index 00000000000..2a34b486fc7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationReactiveIntegrationTests.java @@ -0,0 +1,135 @@ +/* + * Copyright 2012-2017 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.freemarker; + +import java.io.StringWriter; +import java.util.Locale; + +import org.junit.After; +import org.junit.Test; +import reactor.core.publisher.Mono; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext; +import org.springframework.http.MediaType; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import org.springframework.web.reactive.result.view.View; +import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfig; +import org.springframework.web.reactive.result.view.freemarker.FreeMarkerConfigurer; +import org.springframework.web.reactive.result.view.freemarker.FreeMarkerViewResolver; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link FreeMarkerAutoConfiguration} Reactive support. + * + * @author Brian Clozel + */ +public class FreeMarkerAutoConfigurationReactiveIntegrationTests { + + private AnnotationConfigReactiveWebApplicationContext context = new AnnotationConfigReactiveWebApplicationContext(); + + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void defaultConfiguration() { + registerAndRefreshContext(); + assertThat(this.context.getBean(FreeMarkerViewResolver.class)).isNotNull(); + assertThat(this.context.getBean(FreeMarkerConfigurer.class)).isNotNull(); + assertThat(this.context.getBean(FreeMarkerConfig.class)).isNotNull(); + assertThat(this.context.getBean(freemarker.template.Configuration.class)).isNotNull(); + } + + @Test + public void defaultViewResolution() throws Exception { + registerAndRefreshContext(); + MockServerWebExchange exchange = render("home"); + String result = exchange.getResponse().getBodyAsString().block(); + assertThat(result).contains("home"); + assertThat(exchange.getResponse().getHeaders().getContentType()).isEqualTo(MediaType.TEXT_HTML); + } + + @Test + public void customPrefix() throws Exception { + registerAndRefreshContext("spring.freemarker.prefix:prefix/"); + MockServerWebExchange exchange = render("prefixed"); + String result = exchange.getResponse().getBodyAsString().block(); + assertThat(result).contains("prefixed"); + } + + @Test + public void customSuffix() throws Exception { + registerAndRefreshContext("spring.freemarker.suffix:.freemarker"); + MockServerWebExchange exchange = render("suffixed"); + String result = exchange.getResponse().getBodyAsString().block(); + assertThat(result).contains("suffixed"); + } + + @Test + public void customTemplateLoaderPath() throws Exception { + registerAndRefreshContext( + "spring.freemarker.templateLoaderPath:classpath:/custom-templates/"); + MockServerWebExchange exchange = render("custom"); + String result = exchange.getResponse().getBodyAsString().block(); + assertThat(result).contains("custom"); + } + + @SuppressWarnings("deprecation") + @Test + public void customFreeMarkerSettings() { + registerAndRefreshContext("spring.freemarker.settings.boolean_format:yup,nope"); + assertThat(this.context.getBean(FreeMarkerConfigurer.class).getConfiguration() + .getSetting("boolean_format")).isEqualTo("yup,nope"); + } + + @Test + public void renderTemplate() throws Exception { + registerAndRefreshContext(); + FreeMarkerConfigurer freemarker = this.context + .getBean(FreeMarkerConfigurer.class); + StringWriter writer = new StringWriter(); + freemarker.getConfiguration().getTemplate("message.ftl").process(this, writer); + assertThat(writer.toString()).contains("Hello World"); + } + + private void registerAndRefreshContext(String... env) { + TestPropertyValues.of(env).applyTo(this.context); + this.context.register(FreeMarkerAutoConfiguration.class); + this.context.refresh(); + } + + public String getGreeting() { + return "Hello World"; + } + + private MockServerWebExchange render(String viewName) throws Exception { + FreeMarkerViewResolver resolver = this.context + .getBean(FreeMarkerViewResolver.class); + Mono view = resolver.resolveViewName(viewName, Locale.UK); + MockServerWebExchange exchange = MockServerWebExchange + .from(MockServerHttpRequest.get("/path")); + view.flatMap(v -> v.render(null, MediaType.TEXT_HTML, exchange)).block(); + return exchange; + } +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationServletIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationServletIntegrationTests.java new file mode 100644 index 00000000000..b628627733b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationServletIntegrationTests.java @@ -0,0 +1,189 @@ +/* + * Copyright 2012-2017 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.freemarker; + +import java.io.StringWriter; +import java.util.Locale; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.springframework.boot.test.util.TestPropertyValues; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.mock.web.MockServletContext; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.View; +import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; +import org.springframework.web.servlet.support.RequestContext; +import org.springframework.web.servlet.view.AbstractTemplateViewResolver; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfig; +import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; +import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link FreeMarkerAutoConfiguration} Servlet support. + * + * @author Andy Wilkinson + * @author Kazuki Shimizu + */ +public class FreeMarkerAutoConfigurationServletIntegrationTests { + + private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); + + @Before + public void setupContext() { + this.context.setServletContext(new MockServletContext()); + } + + @After + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @Test + public void defaultConfiguration() { + registerAndRefreshContext(); + assertThat(this.context.getBean(FreeMarkerViewResolver.class)).isNotNull(); + assertThat(this.context.getBean(FreeMarkerConfigurer.class)).isNotNull(); + assertThat(this.context.getBean(FreeMarkerConfig.class)).isNotNull(); + assertThat(this.context.getBean(freemarker.template.Configuration.class)).isNotNull(); + } + + @Test + public void defaultViewResolution() throws Exception { + registerAndRefreshContext(); + MockHttpServletResponse response = render("home"); + String result = response.getContentAsString(); + assertThat(result).contains("home"); + assertThat(response.getContentType()).isEqualTo("text/html;charset=UTF-8"); + } + + @Test + public void customContentType() throws Exception { + registerAndRefreshContext("spring.freemarker.contentType:application/json"); + MockHttpServletResponse response = render("home"); + String result = response.getContentAsString(); + assertThat(result).contains("home"); + assertThat(response.getContentType()).isEqualTo("application/json;charset=UTF-8"); + } + + @Test + public void customPrefix() throws Exception { + registerAndRefreshContext("spring.freemarker.prefix:prefix/"); + MockHttpServletResponse response = render("prefixed"); + String result = response.getContentAsString(); + assertThat(result).contains("prefixed"); + } + + @Test + public void customSuffix() throws Exception { + registerAndRefreshContext("spring.freemarker.suffix:.freemarker"); + MockHttpServletResponse response = render("suffixed"); + String result = response.getContentAsString(); + assertThat(result).contains("suffixed"); + } + + @Test + public void customTemplateLoaderPath() throws Exception { + registerAndRefreshContext( + "spring.freemarker.templateLoaderPath:classpath:/custom-templates/"); + MockHttpServletResponse response = render("custom"); + String result = response.getContentAsString(); + assertThat(result).contains("custom"); + } + + @Test + public void disableCache() { + registerAndRefreshContext("spring.freemarker.cache:false"); + assertThat(this.context.getBean(FreeMarkerViewResolver.class).getCacheLimit()) + .isEqualTo(0); + } + + @Test + public void allowSessionOverride() { + registerAndRefreshContext("spring.freemarker.allow-session-override:true"); + AbstractTemplateViewResolver viewResolver = this.context + .getBean(FreeMarkerViewResolver.class); + assertThat(ReflectionTestUtils.getField(viewResolver, "allowSessionOverride")) + .isEqualTo(true); + } + + @SuppressWarnings("deprecation") + @Test + public void customFreeMarkerSettings() { + registerAndRefreshContext("spring.freemarker.settings.boolean_format:yup,nope"); + assertThat(this.context.getBean(FreeMarkerConfigurer.class).getConfiguration() + .getSetting("boolean_format")).isEqualTo("yup,nope"); + } + + @Test + public void renderTemplate() throws Exception { + registerAndRefreshContext(); + FreeMarkerConfigurer freemarker = this.context + .getBean(FreeMarkerConfigurer.class); + StringWriter writer = new StringWriter(); + freemarker.getConfiguration().getTemplate("message.ftl").process(this, writer); + assertThat(writer.toString()).contains("Hello World"); + } + + @Test + public void registerResourceHandlingFilterDisabledByDefault() throws Exception { + registerAndRefreshContext(); + assertThat(this.context.getBeansOfType(ResourceUrlEncodingFilter.class)) + .isEmpty(); + } + + @Test + public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() + throws Exception { + registerAndRefreshContext("spring.resources.chain.enabled:true"); + assertThat(this.context.getBean(ResourceUrlEncodingFilter.class)).isNotNull(); + } + + private void registerAndRefreshContext(String... env) { + TestPropertyValues.of(env).applyTo(this.context); + this.context.register(FreeMarkerAutoConfiguration.class); + this.context.refresh(); + } + + public String getGreeting() { + return "Hello World"; + } + + private MockHttpServletResponse render(String viewName) throws Exception { + FreeMarkerViewResolver resolver = this.context + .getBean(FreeMarkerViewResolver.class); + View view = resolver.resolveViewName(viewName, Locale.UK); + assertThat(view).isNotNull(); + HttpServletRequest request = new MockHttpServletRequest(); + request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, + this.context); + MockHttpServletResponse response = new MockHttpServletResponse(); + view.render(null, request, response); + return response; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationTests.java index d7cc3fabcda..feebde30b26 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfigurationTests.java @@ -18,35 +18,20 @@ package org.springframework.boot.autoconfigure.freemarker; import java.io.File; import java.io.StringWriter; -import java.util.Locale; - -import javax.servlet.http.HttpServletRequest; import org.junit.After; -import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.springframework.boot.test.rule.OutputCapture; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.mock.web.MockServletContext; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.View; -import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; -import org.springframework.web.servlet.support.RequestContext; -import org.springframework.web.servlet.view.AbstractTemplateViewResolver; -import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer; -import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; /** - * Tests for {@link FreeMarkerAutoConfiguration}. + * Tests for {@link FreeMarkerAutoConfiguration} * * @author Andy Wilkinson * @author Kazuki Shimizu @@ -56,25 +41,28 @@ public class FreeMarkerAutoConfigurationTests { @Rule public OutputCapture output = new OutputCapture(); - private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); + private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - @Before - public void setupContext() { - this.context.setServletContext(new MockServletContext()); + private void registerAndRefreshContext(String... env) { + TestPropertyValues.of(env).applyTo(this.context); + this.context.register(FreeMarkerAutoConfiguration.class); + this.context.refresh(); } - @After - public void close() { - if (this.context != null) { - this.context.close(); + @Test + public void renderNonWebAppTemplate() throws Exception { + try (AnnotationConfigApplicationContext customContext = new AnnotationConfigApplicationContext( + FreeMarkerAutoConfiguration.class)) { + freemarker.template.Configuration freemarker = customContext + .getBean(freemarker.template.Configuration.class); + StringWriter writer = new StringWriter(); + freemarker.getTemplate("message.ftl").process(this, writer); + assertThat(writer.toString()).contains("Hello World"); } } - @Test - public void defaultConfiguration() { - registerAndRefreshContext(); - assertThat(this.context.getBean(FreeMarkerViewResolver.class)).isNotNull(); - assertThat(this.context.getBean(FreeMarkerConfigurer.class)).isNotNull(); + public String getGreeting() { + return "Hello World"; } @Test @@ -98,130 +86,11 @@ public class FreeMarkerAutoConfigurationTests { + "classpath:/does-not-exist/,classpath:/templates/empty-directory/"); } - @Test - public void defaultViewResolution() throws Exception { - registerAndRefreshContext(); - MockHttpServletResponse response = render("home"); - String result = response.getContentAsString(); - assertThat(result).contains("home"); - assertThat(response.getContentType()).isEqualTo("text/html;charset=UTF-8"); - } - - @Test - public void customContentType() throws Exception { - registerAndRefreshContext("spring.freemarker.contentType:application/json"); - MockHttpServletResponse response = render("home"); - String result = response.getContentAsString(); - assertThat(result).contains("home"); - assertThat(response.getContentType()).isEqualTo("application/json;charset=UTF-8"); - } - - @Test - public void customPrefix() throws Exception { - registerAndRefreshContext("spring.freemarker.prefix:prefix/"); - MockHttpServletResponse response = render("prefixed"); - String result = response.getContentAsString(); - assertThat(result).contains("prefixed"); - } - - @Test - public void customSuffix() throws Exception { - registerAndRefreshContext("spring.freemarker.suffix:.freemarker"); - MockHttpServletResponse response = render("suffixed"); - String result = response.getContentAsString(); - assertThat(result).contains("suffixed"); - } - - @Test - public void customTemplateLoaderPath() throws Exception { - registerAndRefreshContext( - "spring.freemarker.templateLoaderPath:classpath:/custom-templates/"); - MockHttpServletResponse response = render("custom"); - String result = response.getContentAsString(); - assertThat(result).contains("custom"); - } - - @Test - public void disableCache() { - registerAndRefreshContext("spring.freemarker.cache:false"); - assertThat(this.context.getBean(FreeMarkerViewResolver.class).getCacheLimit()) - .isEqualTo(0); - } - - @Test - public void allowSessionOverride() { - registerAndRefreshContext("spring.freemarker.allow-session-override:true"); - AbstractTemplateViewResolver viewResolver = this.context - .getBean(FreeMarkerViewResolver.class); - assertThat(ReflectionTestUtils.getField(viewResolver, "allowSessionOverride")) - .isEqualTo(true); - } - - @SuppressWarnings("deprecation") - @Test - public void customFreeMarkerSettings() { - registerAndRefreshContext("spring.freemarker.settings.boolean_format:yup,nope"); - assertThat(this.context.getBean(FreeMarkerConfigurer.class).getConfiguration() - .getSetting("boolean_format")).isEqualTo("yup,nope"); - } - - @Test - public void renderTemplate() throws Exception { - registerAndRefreshContext(); - FreeMarkerConfigurer freemarker = this.context - .getBean(FreeMarkerConfigurer.class); - StringWriter writer = new StringWriter(); - freemarker.getConfiguration().getTemplate("message.ftl").process(this, writer); - assertThat(writer.toString()).contains("Hello World"); - } - - @Test - public void renderNonWebAppTemplate() throws Exception { - try (AnnotationConfigApplicationContext customContext = new AnnotationConfigApplicationContext( - FreeMarkerAutoConfiguration.class)) { - freemarker.template.Configuration freemarker = customContext - .getBean(freemarker.template.Configuration.class); - StringWriter writer = new StringWriter(); - freemarker.getTemplate("message.ftl").process(this, writer); - assertThat(writer.toString()).contains("Hello World"); + @After + public void close() { + if (this.context != null) { + this.context.close(); } } - @Test - public void registerResourceHandlingFilterDisabledByDefault() throws Exception { - registerAndRefreshContext(); - assertThat(this.context.getBeansOfType(ResourceUrlEncodingFilter.class)) - .isEmpty(); - } - - @Test - public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() - throws Exception { - registerAndRefreshContext("spring.resources.chain.enabled:true"); - assertThat(this.context.getBean(ResourceUrlEncodingFilter.class)).isNotNull(); - } - - private void registerAndRefreshContext(String... env) { - TestPropertyValues.of(env).applyTo(this.context); - this.context.register(FreeMarkerAutoConfiguration.class); - this.context.refresh(); - } - - public String getGreeting() { - return "Hello World"; - } - - private MockHttpServletResponse render(String viewName) throws Exception { - FreeMarkerViewResolver resolver = this.context - .getBean(FreeMarkerViewResolver.class); - View view = resolver.resolveViewName(viewName, Locale.UK); - assertThat(view).isNotNull(); - HttpServletRequest request = new MockHttpServletRequest(); - request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, - this.context); - MockHttpServletResponse response = new MockHttpServletResponse(); - view.render(null, request, response); - return response; - } - }