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 9f077cb0dbc..18a47d4e89e 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 89f69be6b2a..b28ff65c1a3 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 991b966b8c0..a5ceca8673e 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 e69de29bb2d..8f364d3623a 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 00000000000..53440f08e73 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/templates/message.html @@ -0,0 +1 @@ +Message: Hello \ No newline at end of file