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
This commit is contained in:
Dave Syer 2014-09-25 13:55:18 +01:00 committed by Phillip Webb
parent 68ff7d4592
commit 304920df07
5 changed files with 53 additions and 5 deletions

View File

@ -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() {

View File

@ -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("<html><body data-foo=\"bar\"></body></html>", 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("<html><body>bar</body></html>", 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();
}
}
}

View File

@ -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"));
}

View File

@ -0,0 +1 @@
<html><body th:text="${foo}">Home</body></html>

View File

@ -0,0 +1 @@
<html><body>Message: <span th:text="${greeting}">Hello</span></body></html>