From 304920df073fd20ae68d77d44a08773b6db7c418 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Thu, 25 Sep 2014 13:55:18 +0100 Subject: [PATCH] Make Thymeleaf @ConditionalOnWebApplication If user creates a Thymeleaf app with a parent-child context then the child should contain all the web-specific pieces (and they are likely to fail fast if they need to be ServletContextAware, or slower if they try to locate a WebApplicationContext at runtime). This can't happen if the view resolver is being added to the parent. Freemarker and Velocity already have similar tests because it is assumed that they should be usable outside a web app, so this change just does the same for Thymeleaf. Fixes gh-1611 --- .../thymeleaf/ThymeleafAutoConfiguration.java | 8 ++-- .../ThymeleafAutoConfigurationTests.java | 45 ++++++++++++++++++- .../BasicErrorControllerIntegrationTest.java | 3 +- .../src/test/resources/templates/home.html | 1 + .../src/test/resources/templates/message.html | 1 + 5 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 spring-boot-autoconfigure/src/test/resources/templates/message.html diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java index 9f077cb0db..18a47d4e89 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfiguration.java @@ -29,6 +29,7 @@ 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.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.bind.RelaxedPropertyResolver; import org.springframework.context.EnvironmentAware; @@ -149,19 +150,20 @@ public class ThymeleafAutoConfiguration { @Configuration @ConditionalOnClass({ Servlet.class }) + @ConditionalOnWebApplication protected static class ThymeleafViewResolverConfiguration implements EnvironmentAware { private RelaxedPropertyResolver environment; + @Autowired + private SpringTemplateEngine templateEngine; + @Override public void setEnvironment(Environment environment) { this.environment = new RelaxedPropertyResolver(environment, "spring.thymeleaf."); } - @Autowired - private SpringTemplateEngine templateEngine; - @Bean @ConditionalOnMissingBean(name = "thymeleafViewResolver") public ThymeleafViewResolver thymeleafViewResolver() { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfigurationTests.java index 89f69be6b2..b28ff65c1a 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/thymeleaf/ThymeleafAutoConfigurationTests.java @@ -30,6 +30,7 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockServletContext; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.support.RequestContext; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; @@ -38,8 +39,10 @@ import org.thymeleaf.spring4.view.ThymeleafViewResolver; import org.thymeleaf.templateresolver.ITemplateResolver; import org.thymeleaf.templateresolver.TemplateResolver; +import static org.hamcrest.Matchers.containsString; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -49,7 +52,7 @@ import static org.junit.Assert.assertTrue; */ public class ThymeleafAutoConfigurationTests { - private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + private AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); @After public void close() { @@ -137,4 +140,44 @@ public class ThymeleafAutoConfigurationTests { context.close(); } + @Test + public void useDataDialect() throws Exception { + this.context.register(ThymeleafAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + TemplateEngine engine = this.context.getBean(TemplateEngine.class); + Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); + String result = engine.process("data-dialect", attrs); + assertEquals("", result); + } + + @Test + public void renderTemplate() throws Exception { + this.context.register(ThymeleafAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + TemplateEngine engine = this.context.getBean(TemplateEngine.class); + Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); + String result = engine.process("home", attrs); + assertEquals("bar", result); + } + + @Test + public void renderNonWebAppTemplate() throws Exception { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + ThymeleafAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + assertEquals(0, context.getBeanNamesForType(ViewResolver.class).length); + try { + TemplateEngine engine = context.getBean(TemplateEngine.class); + Context attrs = new Context(Locale.UK, Collections.singletonMap("greeting", + "Hello World")); + String result = engine.process("message", attrs); + assertThat(result, containsString("Hello World")); + } + finally { + context.close(); + } + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTest.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTest.java index 991b966b8c..a5ceca8673 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTest.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/web/BasicErrorControllerIntegrationTest.java @@ -81,7 +81,8 @@ public class BasicErrorControllerIntegrationTest { "http://localhost:" + this.port + "/bind", Map.class); String resp = entity.getBody().toString(); assertThat(resp, containsString("Error count: 1")); - assertThat(resp, containsString("errors=[{codes=")); + assertThat(resp, containsString("errors=[{")); + assertThat(resp, containsString("codes=[")); assertThat(resp, containsString("org.springframework.validation.BindException")); } diff --git a/spring-boot-autoconfigure/src/test/resources/templates/home.html b/spring-boot-autoconfigure/src/test/resources/templates/home.html index e69de29bb2..8f364d3623 100644 --- a/spring-boot-autoconfigure/src/test/resources/templates/home.html +++ b/spring-boot-autoconfigure/src/test/resources/templates/home.html @@ -0,0 +1 @@ +Home \ No newline at end of file diff --git a/spring-boot-autoconfigure/src/test/resources/templates/message.html b/spring-boot-autoconfigure/src/test/resources/templates/message.html new file mode 100644 index 0000000000..53440f08e7 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/templates/message.html @@ -0,0 +1 @@ +Message: Hello \ No newline at end of file