|
|
|
|
@ -26,7 +26,6 @@ import javax.servlet.DispatcherType;
@@ -26,7 +26,6 @@ import javax.servlet.DispatcherType;
|
|
|
|
|
|
|
|
|
|
import nz.net.ultraq.thymeleaf.LayoutDialect; |
|
|
|
|
import nz.net.ultraq.thymeleaf.decorators.strategies.GroupingStrategy; |
|
|
|
|
import org.junit.After; |
|
|
|
|
import org.junit.Rule; |
|
|
|
|
import org.junit.Test; |
|
|
|
|
import org.thymeleaf.TemplateEngine; |
|
|
|
|
@ -38,16 +37,14 @@ import org.thymeleaf.spring5.view.ThymeleafView;
@@ -38,16 +37,14 @@ import org.thymeleaf.spring5.view.ThymeleafView;
|
|
|
|
|
import org.thymeleaf.spring5.view.ThymeleafViewResolver; |
|
|
|
|
import org.thymeleaf.templateresolver.ITemplateResolver; |
|
|
|
|
|
|
|
|
|
import org.springframework.boot.autoconfigure.ImportAutoConfiguration; |
|
|
|
|
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; |
|
|
|
|
import org.springframework.boot.autoconfigure.AutoConfigurations; |
|
|
|
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner; |
|
|
|
|
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; |
|
|
|
|
import org.springframework.boot.test.rule.OutputCapture; |
|
|
|
|
import org.springframework.boot.test.util.TestPropertyValues; |
|
|
|
|
import org.springframework.boot.web.servlet.FilterRegistrationBean; |
|
|
|
|
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter; |
|
|
|
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext; |
|
|
|
|
import org.springframework.context.annotation.Bean; |
|
|
|
|
import org.springframework.context.annotation.Configuration; |
|
|
|
|
import org.springframework.context.annotation.Import; |
|
|
|
|
import org.springframework.mock.web.MockHttpServletRequest; |
|
|
|
|
import org.springframework.mock.web.MockHttpServletResponse; |
|
|
|
|
import org.springframework.mock.web.MockServletContext; |
|
|
|
|
@ -55,13 +52,13 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
@@ -55,13 +52,13 @@ import org.springframework.security.authentication.TestingAuthenticationToken;
|
|
|
|
|
import org.springframework.security.core.context.SecurityContextHolder; |
|
|
|
|
import org.springframework.security.core.context.SecurityContextImpl; |
|
|
|
|
import org.springframework.test.util.ReflectionTestUtils; |
|
|
|
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; |
|
|
|
|
import org.springframework.web.servlet.ViewResolver; |
|
|
|
|
import org.springframework.web.servlet.resource.ResourceUrlEncodingFilter; |
|
|
|
|
import org.springframework.web.servlet.support.RequestContext; |
|
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
|
import static org.hamcrest.Matchers.containsString; |
|
|
|
|
import static org.hamcrest.Matchers.not; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Tests for {@link ThymeleafAutoConfiguration} in Servlet-based applications. |
|
|
|
|
@ -78,271 +75,284 @@ public class ThymeleafServletAutoConfigurationTests {
@@ -78,271 +75,284 @@ public class ThymeleafServletAutoConfigurationTests {
|
|
|
|
|
@Rule |
|
|
|
|
public OutputCapture output = new OutputCapture(); |
|
|
|
|
|
|
|
|
|
private AnnotationConfigWebApplicationContext context; |
|
|
|
|
|
|
|
|
|
@After |
|
|
|
|
public void close() { |
|
|
|
|
if (this.context != null) { |
|
|
|
|
this.context.close(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
private final WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() |
|
|
|
|
.withConfiguration(AutoConfigurations.of(ThymeleafAutoConfiguration.class)); |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void createFromConfigClass() { |
|
|
|
|
load(BaseConfiguration.class, "spring.thymeleaf.mode:HTML", |
|
|
|
|
"spring.thymeleaf.suffix:"); |
|
|
|
|
TemplateEngine engine = this.context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); |
|
|
|
|
String result = engine.process("template.html", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html>bar</html>"); |
|
|
|
|
this.contextRunner.withPropertyValues("spring.thymeleaf.mode:HTML", |
|
|
|
|
"spring.thymeleaf.suffix:").run((context) -> { |
|
|
|
|
assertThat(context).hasSingleBean(TemplateEngine.class); |
|
|
|
|
TemplateEngine engine = context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK, |
|
|
|
|
Collections.singletonMap("foo", "bar")); |
|
|
|
|
String result = engine.process("template.html", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html>bar</html>"); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void overrideCharacterEncoding() { |
|
|
|
|
load(BaseConfiguration.class, "spring.thymeleaf.encoding:UTF-16"); |
|
|
|
|
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class); |
|
|
|
|
assertThat(resolver instanceof SpringResourceTemplateResolver).isTrue(); |
|
|
|
|
assertThat(((SpringResourceTemplateResolver) resolver).getCharacterEncoding()) |
|
|
|
|
.isEqualTo("UTF-16"); |
|
|
|
|
ThymeleafViewResolver views = this.context.getBean(ThymeleafViewResolver.class); |
|
|
|
|
assertThat(views.getCharacterEncoding()).isEqualTo("UTF-16"); |
|
|
|
|
assertThat(views.getContentType()).isEqualTo("text/html;charset=UTF-16"); |
|
|
|
|
this.contextRunner.withPropertyValues("spring.thymeleaf.encoding:UTF-16") |
|
|
|
|
.run((context) -> { |
|
|
|
|
ITemplateResolver resolver = context.getBean(ITemplateResolver.class); |
|
|
|
|
assertThat(resolver) |
|
|
|
|
.isInstanceOf(SpringResourceTemplateResolver.class); |
|
|
|
|
assertThat(((SpringResourceTemplateResolver) resolver) |
|
|
|
|
.getCharacterEncoding()).isEqualTo("UTF-16"); |
|
|
|
|
ThymeleafViewResolver views = context |
|
|
|
|
.getBean(ThymeleafViewResolver.class); |
|
|
|
|
assertThat(views.getCharacterEncoding()).isEqualTo("UTF-16"); |
|
|
|
|
assertThat(views.getContentType()) |
|
|
|
|
.isEqualTo("text/html;charset=UTF-16"); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void overrideDisableProducePartialOutputWhileProcessing() { |
|
|
|
|
load(BaseConfiguration.class, |
|
|
|
|
"spring.thymeleaf.servlet.produce-partial-output-while-processing:false"); |
|
|
|
|
assertThat(this.context.getBean(ThymeleafViewResolver.class) |
|
|
|
|
.getProducePartialOutputWhileProcessing()).isFalse(); |
|
|
|
|
this.contextRunner.withPropertyValues( |
|
|
|
|
"spring.thymeleaf.servlet.produce-partial-output-while-processing:false") |
|
|
|
|
.run((context) -> assertThat(context.getBean(ThymeleafViewResolver.class) |
|
|
|
|
.getProducePartialOutputWhileProcessing()).isFalse()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void disableProducePartialOutputWhileProcessingIsEnabledByDefault() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
assertThat(this.context.getBean(ThymeleafViewResolver.class) |
|
|
|
|
.getProducePartialOutputWhileProcessing()).isTrue(); |
|
|
|
|
this.contextRunner |
|
|
|
|
.run((context) -> assertThat(context.getBean(ThymeleafViewResolver.class) |
|
|
|
|
.getProducePartialOutputWhileProcessing()).isTrue()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void overrideTemplateResolverOrder() { |
|
|
|
|
load(BaseConfiguration.class, "spring.thymeleaf.templateResolverOrder:25"); |
|
|
|
|
ITemplateResolver resolver = this.context.getBean(ITemplateResolver.class); |
|
|
|
|
assertThat(resolver.getOrder()).isEqualTo(Integer.valueOf(25)); |
|
|
|
|
this.contextRunner.withPropertyValues("spring.thymeleaf.templateResolverOrder:25") |
|
|
|
|
.run((context) -> assertThat( |
|
|
|
|
context.getBean(ITemplateResolver.class).getOrder()) |
|
|
|
|
.isEqualTo(Integer.valueOf(25))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void overrideViewNames() { |
|
|
|
|
load(BaseConfiguration.class, "spring.thymeleaf.viewNames:foo,bar"); |
|
|
|
|
ThymeleafViewResolver views = this.context.getBean(ThymeleafViewResolver.class); |
|
|
|
|
assertThat(views.getViewNames()).isEqualTo(new String[] { "foo", "bar" }); |
|
|
|
|
this.contextRunner.withPropertyValues("spring.thymeleaf.viewNames:foo,bar") |
|
|
|
|
.run((context) -> assertThat( |
|
|
|
|
context.getBean(ThymeleafViewResolver.class).getViewNames()) |
|
|
|
|
.isEqualTo(new String[] { "foo", "bar" })); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void overrideEnableSpringElCompiler() { |
|
|
|
|
load(BaseConfiguration.class, "spring.thymeleaf.enable-spring-el-compiler:true"); |
|
|
|
|
assertThat(this.context.getBean(SpringTemplateEngine.class) |
|
|
|
|
.getEnableSpringELCompiler()).isTrue(); |
|
|
|
|
this.contextRunner |
|
|
|
|
.withPropertyValues("spring.thymeleaf.enable-spring-el-compiler:true") |
|
|
|
|
.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class) |
|
|
|
|
.getEnableSpringELCompiler()).isTrue()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void enableSpringElCompilerIsDisabledByDefault() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
assertThat(this.context.getBean(SpringTemplateEngine.class) |
|
|
|
|
.getEnableSpringELCompiler()).isFalse(); |
|
|
|
|
this.contextRunner.run((context) -> assertThat( |
|
|
|
|
context.getBean(SpringTemplateEngine.class).getEnableSpringELCompiler()) |
|
|
|
|
.isFalse()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void overrideRenderHiddenMarkersBeforeCheckboxes() { |
|
|
|
|
load(BaseConfiguration.class, |
|
|
|
|
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true"); |
|
|
|
|
assertThat(this.context.getBean(SpringTemplateEngine.class) |
|
|
|
|
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue(); |
|
|
|
|
this.contextRunner |
|
|
|
|
.withPropertyValues( |
|
|
|
|
"spring.thymeleaf.render-hidden-markers-before-checkboxes:true") |
|
|
|
|
.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class) |
|
|
|
|
.getRenderHiddenMarkersBeforeCheckboxes()).isTrue()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void enableRenderHiddenMarkersBeforeCheckboxesIsDisabledByDefault() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
assertThat(this.context.getBean(SpringTemplateEngine.class) |
|
|
|
|
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse(); |
|
|
|
|
this.contextRunner |
|
|
|
|
.run((context) -> assertThat(context.getBean(SpringTemplateEngine.class) |
|
|
|
|
.getRenderHiddenMarkersBeforeCheckboxes()).isFalse()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void templateLocationDoesNotExist() { |
|
|
|
|
load(BaseConfiguration.class, |
|
|
|
|
"spring.thymeleaf.prefix:classpath:/no-such-directory/"); |
|
|
|
|
this.output.expect(containsString("Cannot find template location")); |
|
|
|
|
this.contextRunner |
|
|
|
|
.withPropertyValues( |
|
|
|
|
"spring.thymeleaf.prefix:classpath:/no-such-directory/") |
|
|
|
|
.run((context) -> this.output |
|
|
|
|
.expect(containsString("Cannot find template location"))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void templateLocationEmpty() { |
|
|
|
|
new File("target/test-classes/templates/empty-directory").mkdir(); |
|
|
|
|
load(BaseConfiguration.class, |
|
|
|
|
"spring.thymeleaf.prefix:classpath:/templates/empty-directory/"); |
|
|
|
|
this.contextRunner |
|
|
|
|
.withPropertyValues( |
|
|
|
|
"spring.thymeleaf.prefix:classpath:/templates/empty-directory/") |
|
|
|
|
.run((context) -> this.output |
|
|
|
|
.expect(not(containsString("Cannot find template location")))); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void createLayoutFromConfigClass() throws Exception { |
|
|
|
|
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); |
|
|
|
|
context.register(ThymeleafAutoConfiguration.class, |
|
|
|
|
PropertyPlaceholderAutoConfiguration.class); |
|
|
|
|
MockServletContext servletContext = new MockServletContext(); |
|
|
|
|
context.setServletContext(servletContext); |
|
|
|
|
context.refresh(); |
|
|
|
|
ThymeleafView view = (ThymeleafView) context.getBean(ThymeleafViewResolver.class) |
|
|
|
|
.resolveViewName("view", Locale.UK); |
|
|
|
|
MockHttpServletResponse response = new MockHttpServletResponse(); |
|
|
|
|
MockHttpServletRequest request = new MockHttpServletRequest(); |
|
|
|
|
request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, context); |
|
|
|
|
view.render(Collections.singletonMap("foo", "bar"), request, response); |
|
|
|
|
String result = response.getContentAsString(); |
|
|
|
|
assertThat(result).contains("<title>Content</title>"); |
|
|
|
|
assertThat(result).contains("<span>bar</span>"); |
|
|
|
|
context.close(); |
|
|
|
|
public void createLayoutFromConfigClass() { |
|
|
|
|
this.contextRunner.run((context) -> { |
|
|
|
|
ThymeleafView view = (ThymeleafView) context |
|
|
|
|
.getBean(ThymeleafViewResolver.class) |
|
|
|
|
.resolveViewName("view", Locale.UK); |
|
|
|
|
MockHttpServletResponse response = new MockHttpServletResponse(); |
|
|
|
|
MockHttpServletRequest request = new MockHttpServletRequest(); |
|
|
|
|
request.setAttribute(RequestContext.WEB_APPLICATION_CONTEXT_ATTRIBUTE, |
|
|
|
|
context); |
|
|
|
|
view.render(Collections.singletonMap("foo", "bar"), request, response); |
|
|
|
|
String result = response.getContentAsString(); |
|
|
|
|
assertThat(result).contains("<title>Content</title>"); |
|
|
|
|
assertThat(result).contains("<span>bar</span>"); |
|
|
|
|
context.close(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void useDataDialect() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
TemplateEngine engine = this.context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); |
|
|
|
|
String result = engine.process("data-dialect", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>"); |
|
|
|
|
this.contextRunner.run((context) -> { |
|
|
|
|
TemplateEngine engine = context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK, |
|
|
|
|
Collections.singletonMap("foo", "bar")); |
|
|
|
|
String result = engine.process("data-dialect", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body data-foo=\"bar\"></body></html>"); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void useJava8TimeDialect() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
TemplateEngine engine = this.context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK); |
|
|
|
|
String result = engine.process("java8time-dialect", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>"); |
|
|
|
|
this.contextRunner.run((context) -> { |
|
|
|
|
TemplateEngine engine = context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK); |
|
|
|
|
String result = engine.process("java8time-dialect", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body>2015-11-24</body></html>"); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void useSecurityDialect() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
TemplateEngine engine = this.context.getBean(TemplateEngine.class); |
|
|
|
|
WebContext attrs = new WebContext(new MockHttpServletRequest(), |
|
|
|
|
new MockHttpServletResponse(), new MockServletContext()); |
|
|
|
|
try { |
|
|
|
|
SecurityContextHolder.setContext(new SecurityContextImpl( |
|
|
|
|
new TestingAuthenticationToken("alice", "admin"))); |
|
|
|
|
String result = engine.process("security-dialect", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body><div>alice</div></body></html>" |
|
|
|
|
+ System.lineSeparator()); |
|
|
|
|
} |
|
|
|
|
finally { |
|
|
|
|
SecurityContextHolder.clearContext(); |
|
|
|
|
} |
|
|
|
|
this.contextRunner.run((context) -> { |
|
|
|
|
TemplateEngine engine = context.getBean(TemplateEngine.class); |
|
|
|
|
WebContext attrs = new WebContext(new MockHttpServletRequest(), |
|
|
|
|
new MockHttpServletResponse(), new MockServletContext()); |
|
|
|
|
try { |
|
|
|
|
SecurityContextHolder.setContext(new SecurityContextImpl( |
|
|
|
|
new TestingAuthenticationToken("alice", "admin"))); |
|
|
|
|
String result = engine.process("security-dialect", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body><div>alice</div></body></html>" |
|
|
|
|
+ System.lineSeparator()); |
|
|
|
|
} |
|
|
|
|
finally { |
|
|
|
|
SecurityContextHolder.clearContext(); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void renderTemplate() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
TemplateEngine engine = this.context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK, Collections.singletonMap("foo", "bar")); |
|
|
|
|
String result = engine.process("home", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body>bar</body></html>"); |
|
|
|
|
this.contextRunner.run((context) -> { |
|
|
|
|
TemplateEngine engine = context.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK, |
|
|
|
|
Collections.singletonMap("foo", "bar")); |
|
|
|
|
String result = engine.process("home", attrs); |
|
|
|
|
assertThat(result).isEqualTo("<html><body>bar</body></html>"); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void renderNonWebAppTemplate() { |
|
|
|
|
try (AnnotationConfigApplicationContext customContext = new AnnotationConfigApplicationContext( |
|
|
|
|
ThymeleafAutoConfiguration.class, |
|
|
|
|
PropertyPlaceholderAutoConfiguration.class)) { |
|
|
|
|
assertThat(customContext.getBeanNamesForType(ViewResolver.class).length) |
|
|
|
|
.isEqualTo(0); |
|
|
|
|
TemplateEngine engine = customContext.getBean(TemplateEngine.class); |
|
|
|
|
Context attrs = new Context(Locale.UK, |
|
|
|
|
Collections.singletonMap("greeting", "Hello World")); |
|
|
|
|
String result = engine.process("message", attrs); |
|
|
|
|
assertThat(result).contains("Hello World"); |
|
|
|
|
} |
|
|
|
|
new ApplicationContextRunner() |
|
|
|
|
.withConfiguration( |
|
|
|
|
AutoConfigurations.of(ThymeleafAutoConfiguration.class)) |
|
|
|
|
.run((context) -> { |
|
|
|
|
assertThat(context).doesNotHaveBean(ViewResolver.class); |
|
|
|
|
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).contains("Hello World"); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void registerResourceHandlingFilterDisabledByDefault() { |
|
|
|
|
load(BaseConfiguration.class); |
|
|
|
|
assertThat(this.context.getBeansOfType(FilterRegistrationBean.class)).isEmpty(); |
|
|
|
|
this.contextRunner.run((context) -> assertThat(context) |
|
|
|
|
.doesNotHaveBean(FilterRegistrationBean.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void registerResourceHandlingFilterOnlyIfResourceChainIsEnabled() { |
|
|
|
|
load(BaseConfiguration.class, "spring.resources.chain.enabled:true"); |
|
|
|
|
FilterRegistrationBean<?> registration = this.context |
|
|
|
|
.getBean(FilterRegistrationBean.class); |
|
|
|
|
assertThat(registration.getFilter()) |
|
|
|
|
.isInstanceOf(ResourceUrlEncodingFilter.class); |
|
|
|
|
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes", |
|
|
|
|
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR)); |
|
|
|
|
this.contextRunner.withPropertyValues("spring.resources.chain.enabled:true") |
|
|
|
|
.run((context) -> { |
|
|
|
|
FilterRegistrationBean<?> registration = context |
|
|
|
|
.getBean(FilterRegistrationBean.class); |
|
|
|
|
assertThat(registration.getFilter()) |
|
|
|
|
.isInstanceOf(ResourceUrlEncodingFilter.class); |
|
|
|
|
assertThat(registration).hasFieldOrPropertyWithValue( |
|
|
|
|
"dispatcherTypes", |
|
|
|
|
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR)); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
@SuppressWarnings("rawtypes") |
|
|
|
|
public void registerResourceHandlingFilterWithOtherRegistrationBean() { |
|
|
|
|
// gh-14897
|
|
|
|
|
load(FilterRegistrationOtherConfiguration.class, |
|
|
|
|
"spring.resources.chain.enabled:true"); |
|
|
|
|
Map<String, FilterRegistrationBean> beans = this.context |
|
|
|
|
.getBeansOfType(FilterRegistrationBean.class); |
|
|
|
|
assertThat(beans).hasSize(2); |
|
|
|
|
FilterRegistrationBean registration = beans.values().stream() |
|
|
|
|
.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter) |
|
|
|
|
.findFirst().get(); |
|
|
|
|
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes", |
|
|
|
|
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR)); |
|
|
|
|
this.contextRunner |
|
|
|
|
.withUserConfiguration(FilterRegistrationOtherConfiguration.class) |
|
|
|
|
.withPropertyValues("spring.resources.chain.enabled:true") |
|
|
|
|
.run((context) -> { |
|
|
|
|
Map<String, FilterRegistrationBean> beans = context |
|
|
|
|
.getBeansOfType(FilterRegistrationBean.class); |
|
|
|
|
assertThat(beans).hasSize(2); |
|
|
|
|
FilterRegistrationBean registration = beans.values().stream().filter( |
|
|
|
|
(r) -> r.getFilter() instanceof ResourceUrlEncodingFilter) |
|
|
|
|
.findFirst().get(); |
|
|
|
|
assertThat(registration).hasFieldOrPropertyWithValue( |
|
|
|
|
"dispatcherTypes", |
|
|
|
|
EnumSet.of(DispatcherType.REQUEST, DispatcherType.ERROR)); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
@SuppressWarnings("rawtypes") |
|
|
|
|
public void registerResourceHandlingFilterWithResourceRegistrationBean() { |
|
|
|
|
// gh-14926
|
|
|
|
|
load(FilterRegistrationResourceConfiguration.class, |
|
|
|
|
"spring.resources.chain.enabled:true"); |
|
|
|
|
Map<String, FilterRegistrationBean> beans = this.context |
|
|
|
|
.getBeansOfType(FilterRegistrationBean.class); |
|
|
|
|
assertThat(beans).hasSize(1); |
|
|
|
|
FilterRegistrationBean registration = beans.values().stream() |
|
|
|
|
.filter((r) -> r.getFilter() instanceof ResourceUrlEncodingFilter) |
|
|
|
|
.findFirst().get(); |
|
|
|
|
assertThat(registration).hasFieldOrPropertyWithValue("dispatcherTypes", |
|
|
|
|
EnumSet.of(DispatcherType.INCLUDE)); |
|
|
|
|
this.contextRunner |
|
|
|
|
.withUserConfiguration(FilterRegistrationResourceConfiguration.class) |
|
|
|
|
.withPropertyValues("spring.resources.chain.enabled:true") |
|
|
|
|
.run((context) -> { |
|
|
|
|
Map<String, FilterRegistrationBean> beans = context |
|
|
|
|
.getBeansOfType(FilterRegistrationBean.class); |
|
|
|
|
assertThat(beans).hasSize(1); |
|
|
|
|
FilterRegistrationBean registration = beans.values().stream().filter( |
|
|
|
|
(r) -> r.getFilter() instanceof ResourceUrlEncodingFilter) |
|
|
|
|
.findFirst().get(); |
|
|
|
|
assertThat(registration).hasFieldOrPropertyWithValue( |
|
|
|
|
"dispatcherTypes", EnumSet.of(DispatcherType.INCLUDE)); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void layoutDialectCanBeCustomized() { |
|
|
|
|
load(LayoutDialectConfiguration.class); |
|
|
|
|
LayoutDialect layoutDialect = this.context.getBean(LayoutDialect.class); |
|
|
|
|
assertThat(ReflectionTestUtils.getField(layoutDialect, "sortingStrategy")) |
|
|
|
|
.isInstanceOf(GroupingStrategy.class); |
|
|
|
|
this.contextRunner.withUserConfiguration(LayoutDialectConfiguration.class) |
|
|
|
|
.run((context) -> assertThat(ReflectionTestUtils.getField( |
|
|
|
|
context.getBean(LayoutDialect.class), "sortingStrategy")) |
|
|
|
|
.isInstanceOf(GroupingStrategy.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void cachingCanBeDisabled() { |
|
|
|
|
load(BaseConfiguration.class, "spring.thymeleaf.cache:false"); |
|
|
|
|
assertThat(this.context.getBean(ThymeleafViewResolver.class).isCache()).isFalse(); |
|
|
|
|
SpringResourceTemplateResolver templateResolver = this.context |
|
|
|
|
.getBean(SpringResourceTemplateResolver.class); |
|
|
|
|
assertThat(templateResolver.isCacheable()).isFalse(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private void load(Class<?> config, String... envVariables) { |
|
|
|
|
this.context = new AnnotationConfigWebApplicationContext(); |
|
|
|
|
TestPropertyValues.of(envVariables).applyTo(this.context); |
|
|
|
|
this.context.register(config); |
|
|
|
|
this.context.refresh(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
@ImportAutoConfiguration({ ThymeleafAutoConfiguration.class, |
|
|
|
|
PropertyPlaceholderAutoConfiguration.class }) |
|
|
|
|
static class BaseConfiguration { |
|
|
|
|
|
|
|
|
|
this.contextRunner.withPropertyValues("spring.thymeleaf.cache:false") |
|
|
|
|
.run((context) -> { |
|
|
|
|
assertThat(context.getBean(ThymeleafViewResolver.class).isCache()) |
|
|
|
|
.isFalse(); |
|
|
|
|
SpringResourceTemplateResolver templateResolver = context |
|
|
|
|
.getBean(SpringResourceTemplateResolver.class); |
|
|
|
|
assertThat(templateResolver.isCacheable()).isFalse(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
@Import(BaseConfiguration.class) |
|
|
|
|
static class LayoutDialectConfiguration { |
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
@ -353,12 +363,11 @@ public class ThymeleafServletAutoConfigurationTests {
@@ -353,12 +363,11 @@ public class ThymeleafServletAutoConfigurationTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
@Import(BaseConfiguration.class) |
|
|
|
|
static class FilterRegistrationResourceConfiguration { |
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
public FilterRegistrationBean<ResourceUrlEncodingFilter> filterRegistration() { |
|
|
|
|
FilterRegistrationBean<ResourceUrlEncodingFilter> bean = new FilterRegistrationBean<ResourceUrlEncodingFilter>( |
|
|
|
|
FilterRegistrationBean<ResourceUrlEncodingFilter> bean = new FilterRegistrationBean<>( |
|
|
|
|
new ResourceUrlEncodingFilter()); |
|
|
|
|
bean.setDispatcherTypes(EnumSet.of(DispatcherType.INCLUDE)); |
|
|
|
|
return bean; |
|
|
|
|
@ -367,13 +376,11 @@ public class ThymeleafServletAutoConfigurationTests {
@@ -367,13 +376,11 @@ public class ThymeleafServletAutoConfigurationTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Configuration |
|
|
|
|
@Import(BaseConfiguration.class) |
|
|
|
|
static class FilterRegistrationOtherConfiguration { |
|
|
|
|
|
|
|
|
|
@Bean |
|
|
|
|
public FilterRegistrationBean<OrderedCharacterEncodingFilter> filterRegistration() { |
|
|
|
|
return new FilterRegistrationBean<OrderedCharacterEncodingFilter>( |
|
|
|
|
new OrderedCharacterEncodingFilter()); |
|
|
|
|
return new FilterRegistrationBean<>(new OrderedCharacterEncodingFilter()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|