Allow template lookup caching to be disabled
Extract TemplateAvailabilityProvider caching logic to a new TemplateAvailabilityProviders class and provide property support to disable it. Also update DevToolsPropertyDefaultsPostProcessor to automatically set the property. Fixes gh-5989
This commit is contained in:
parent
14c7a1284e
commit
ccdcad757a
|
@ -0,0 +1,178 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2016 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.template;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import org.springframework.boot.bind.RelaxedPropertyResolver;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.env.Environment;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection of {@link TemplateAvailabilityProvider} beans that can be used to check
|
||||||
|
* which (if any) templating engine supports a given view. Caches responses unless the
|
||||||
|
* {@code spring.template.provider.cache} property is set to {@code false}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
* @since 1.4.0
|
||||||
|
*/
|
||||||
|
public class TemplateAvailabilityProviders {
|
||||||
|
|
||||||
|
private final List<TemplateAvailabilityProvider> providers;
|
||||||
|
|
||||||
|
private static final int CACHE_LIMIT = 1024;
|
||||||
|
|
||||||
|
private static final TemplateAvailabilityProvider NONE = new NoTemplateAvailabilityProvider();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* resolved template views, returning already cached instances without a global lock.
|
||||||
|
*/
|
||||||
|
private final Map<String, TemplateAvailabilityProvider> resolved = new ConcurrentHashMap<String, TemplateAvailabilityProvider>(
|
||||||
|
CACHE_LIMIT);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map from view name resolve template view, synchronized when accessed.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
private final Map<String, TemplateAvailabilityProvider> cache = new LinkedHashMap<String, TemplateAvailabilityProvider>(
|
||||||
|
CACHE_LIMIT, 0.75f, true) {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean removeEldestEntry(
|
||||||
|
Map.Entry<String, TemplateAvailabilityProvider> eldest) {
|
||||||
|
if (size() > CACHE_LIMIT) {
|
||||||
|
TemplateAvailabilityProviders.this.resolved.remove(eldest.getKey());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link TemplateAvailabilityProviders} instance.
|
||||||
|
* @param applicationContext the source application context
|
||||||
|
*/
|
||||||
|
public TemplateAvailabilityProviders(ApplicationContext applicationContext) {
|
||||||
|
this(applicationContext == null ? null : applicationContext.getClassLoader());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link TemplateAvailabilityProviders} instance.
|
||||||
|
* @param classLoader the source class loader
|
||||||
|
*/
|
||||||
|
public TemplateAvailabilityProviders(ClassLoader classLoader) {
|
||||||
|
Assert.notNull(classLoader, "ClassLoader must not be null");
|
||||||
|
this.providers = SpringFactoriesLoader
|
||||||
|
.loadFactories(TemplateAvailabilityProvider.class, classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new {@link TemplateAvailabilityProviders} instance.
|
||||||
|
* @param providers the underlying providers
|
||||||
|
*/
|
||||||
|
protected TemplateAvailabilityProviders(
|
||||||
|
Collection<? extends TemplateAvailabilityProvider> providers) {
|
||||||
|
Assert.notNull(providers, "Providers must not be null");
|
||||||
|
this.providers = new ArrayList<TemplateAvailabilityProvider>(providers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the underlying providers being used.
|
||||||
|
* @return the providers being used
|
||||||
|
*/
|
||||||
|
public List<TemplateAvailabilityProvider> getProviders() {
|
||||||
|
return this.providers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the provider that can be used to render the given view.
|
||||||
|
* @param view the view to render
|
||||||
|
* @param applicationContext the application context
|
||||||
|
* @return a {@link TemplateAvailabilityProvider} or null
|
||||||
|
*/
|
||||||
|
public TemplateAvailabilityProvider getProvider(String view,
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
|
Assert.notNull(applicationContext, "ApplicationContext must not be null");
|
||||||
|
return getProvider(view, applicationContext.getEnvironment(),
|
||||||
|
applicationContext.getClassLoader(), applicationContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the provider that can be used to render the given view.
|
||||||
|
* @param view the view to render
|
||||||
|
* @param environment the environment
|
||||||
|
* @param classLoader the class loader
|
||||||
|
* @param resourceLoader the resource loader
|
||||||
|
* @return a {@link TemplateAvailabilityProvider} or null
|
||||||
|
*/
|
||||||
|
public TemplateAvailabilityProvider getProvider(String view, Environment environment,
|
||||||
|
ClassLoader classLoader, ResourceLoader resourceLoader) {
|
||||||
|
Assert.notNull(view, "View must not be null");
|
||||||
|
Assert.notNull(environment, "Environment must not be null");
|
||||||
|
Assert.notNull(classLoader, "ClassLoader must not be null");
|
||||||
|
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
|
||||||
|
|
||||||
|
RelaxedPropertyResolver propertyResolver = new RelaxedPropertyResolver(
|
||||||
|
environment, "spring.template.provider.");
|
||||||
|
if (!propertyResolver.getProperty("cache", Boolean.class, true)) {
|
||||||
|
return findProvider(view, environment, classLoader, resourceLoader);
|
||||||
|
}
|
||||||
|
TemplateAvailabilityProvider provider = this.resolved.get(view);
|
||||||
|
if (provider == null) {
|
||||||
|
synchronized (this.cache) {
|
||||||
|
provider = findProvider(view, environment, classLoader, resourceLoader);
|
||||||
|
provider = (provider == null ? NONE : provider);
|
||||||
|
this.resolved.put(view, provider);
|
||||||
|
this.cache.put(view, provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (provider == NONE ? null : provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TemplateAvailabilityProvider findProvider(String view,
|
||||||
|
Environment environment, ClassLoader classLoader,
|
||||||
|
ResourceLoader resourceLoader) {
|
||||||
|
for (TemplateAvailabilityProvider candidate : this.providers) {
|
||||||
|
if (candidate.isTemplateAvailable(view, environment, classLoader,
|
||||||
|
resourceLoader)) {
|
||||||
|
return candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class NoTemplateAvailabilityProvider
|
||||||
|
implements TemplateAvailabilityProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTemplateAvailable(String view, Environment environment,
|
||||||
|
ClassLoader classLoader, ResourceLoader resourceLoader) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,17 +18,17 @@ package org.springframework.boot.autoconfigure.web;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.io.Resource;
|
import org.springframework.core.io.Resource;
|
||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.HttpStatus.Series;
|
import org.springframework.http.HttpStatus.Series;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
@ -70,7 +70,7 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||||
|
|
||||||
private final ResourceProperties resourceProperties;
|
private final ResourceProperties resourceProperties;
|
||||||
|
|
||||||
private final List<TemplateAvailabilityProvider> templateAvailabilityProviders;
|
private final TemplateAvailabilityProviders templateAvailabilityProviders;
|
||||||
|
|
||||||
private int order = Ordered.LOWEST_PRECEDENCE;
|
private int order = Ordered.LOWEST_PRECEDENCE;
|
||||||
|
|
||||||
|
@ -81,19 +81,17 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||||
*/
|
*/
|
||||||
public DefaultErrorViewResolver(ApplicationContext applicationContext,
|
public DefaultErrorViewResolver(ApplicationContext applicationContext,
|
||||||
ResourceProperties resourceProperties) {
|
ResourceProperties resourceProperties) {
|
||||||
this(applicationContext, resourceProperties,
|
Assert.notNull(applicationContext, "ApplicationContext must not be null");
|
||||||
loadTemplateAvailabilityProviders(applicationContext));
|
Assert.notNull(resourceProperties, "ResourceProperties must not be null");
|
||||||
}
|
this.applicationContext = applicationContext;
|
||||||
|
this.resourceProperties = resourceProperties;
|
||||||
private static List<TemplateAvailabilityProvider> loadTemplateAvailabilityProviders(
|
this.templateAvailabilityProviders = new TemplateAvailabilityProviders(
|
||||||
ApplicationContext applicationContext) {
|
applicationContext);
|
||||||
return SpringFactoriesLoader.loadFactories(TemplateAvailabilityProvider.class,
|
|
||||||
applicationContext == null ? null : applicationContext.getClassLoader());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultErrorViewResolver(ApplicationContext applicationContext,
|
DefaultErrorViewResolver(ApplicationContext applicationContext,
|
||||||
ResourceProperties resourceProperties,
|
ResourceProperties resourceProperties,
|
||||||
List<TemplateAvailabilityProvider> templateAvailabilityProviders) {
|
TemplateAvailabilityProviders templateAvailabilityProviders) {
|
||||||
Assert.notNull(applicationContext, "ApplicationContext must not be null");
|
Assert.notNull(applicationContext, "ApplicationContext must not be null");
|
||||||
Assert.notNull(resourceProperties, "ResourceProperties must not be null");
|
Assert.notNull(resourceProperties, "ResourceProperties must not be null");
|
||||||
this.applicationContext = applicationContext;
|
this.applicationContext = applicationContext;
|
||||||
|
@ -101,6 +99,14 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||||
this.templateAvailabilityProviders = templateAvailabilityProviders;
|
this.templateAvailabilityProviders = templateAvailabilityProviders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DefaultErrorViewResolver(AnnotationConfigApplicationContext applicationContext,
|
||||||
|
ResourceProperties resourceProperties,
|
||||||
|
TemplateAvailabilityProviders templateAvailabilityProviders) {
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
|
this.resourceProperties = resourceProperties;
|
||||||
|
this.templateAvailabilityProviders = templateAvailabilityProviders;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
|
public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status,
|
||||||
Map<String, Object> model) {
|
Map<String, Object> model) {
|
||||||
|
@ -112,29 +118,20 @@ public class DefaultErrorViewResolver implements ErrorViewResolver, Ordered {
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModelAndView resolve(String viewName, Map<String, Object> model) {
|
private ModelAndView resolve(String viewName, Map<String, Object> model) {
|
||||||
ModelAndView modelAndView = resolveTemplate(viewName, model);
|
String errorViewName = "error/" + viewName;
|
||||||
if (modelAndView == null) {
|
TemplateAvailabilityProvider provider = this.templateAvailabilityProviders
|
||||||
modelAndView = resolveResource(viewName, model);
|
.getProvider(errorViewName, this.applicationContext);
|
||||||
|
if (provider != null) {
|
||||||
|
return new ModelAndView(errorViewName, model);
|
||||||
}
|
}
|
||||||
return modelAndView;
|
return resolveResource(errorViewName, model);
|
||||||
}
|
|
||||||
|
|
||||||
private ModelAndView resolveTemplate(String viewName, Map<String, Object> model) {
|
|
||||||
for (TemplateAvailabilityProvider templateAvailabilityProvider : this.templateAvailabilityProviders) {
|
|
||||||
if (templateAvailabilityProvider.isTemplateAvailable("error/" + viewName,
|
|
||||||
this.applicationContext.getEnvironment(),
|
|
||||||
this.applicationContext.getClassLoader(), this.applicationContext)) {
|
|
||||||
return new ModelAndView("error/" + viewName, model);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
|
private ModelAndView resolveResource(String viewName, Map<String, Object> model) {
|
||||||
for (String location : this.resourceProperties.getStaticLocations()) {
|
for (String location : this.resourceProperties.getStaticLocations()) {
|
||||||
try {
|
try {
|
||||||
Resource resource = this.applicationContext.getResource(location);
|
Resource resource = this.applicationContext.getResource(location);
|
||||||
resource = resource.createRelative("error/" + viewName + ".html");
|
resource = resource.createRelative(viewName + ".html");
|
||||||
if (resource.exists()) {
|
if (resource.exists()) {
|
||||||
return new ModelAndView(new HtmlResourceView(resource), model);
|
return new ModelAndView(new HtmlResourceView(resource), model);
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
|
||||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||||
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
|
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.web.servlet.ErrorPage;
|
import org.springframework.boot.web.servlet.ErrorPage;
|
||||||
|
@ -53,7 +54,6 @@ import org.springframework.context.annotation.Conditional;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.expression.MapAccessor;
|
import org.springframework.context.expression.MapAccessor;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
|
||||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||||
import org.springframework.expression.EvaluationContext;
|
import org.springframework.expression.EvaluationContext;
|
||||||
import org.springframework.expression.Expression;
|
import org.springframework.expression.Expression;
|
||||||
|
@ -166,19 +166,15 @@ public class ErrorMvcAutoConfiguration {
|
||||||
@Override
|
@Override
|
||||||
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
public ConditionOutcome getMatchOutcome(ConditionContext context,
|
||||||
AnnotatedTypeMetadata metadata) {
|
AnnotatedTypeMetadata metadata) {
|
||||||
List<TemplateAvailabilityProvider> availabilityProviders = SpringFactoriesLoader
|
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(
|
||||||
.loadFactories(TemplateAvailabilityProvider.class,
|
|
||||||
context.getClassLoader());
|
context.getClassLoader());
|
||||||
|
TemplateAvailabilityProvider provider = providers.getProvider("error",
|
||||||
for (TemplateAvailabilityProvider availabilityProvider : availabilityProviders) {
|
|
||||||
if (availabilityProvider.isTemplateAvailable("error",
|
|
||||||
context.getEnvironment(), context.getClassLoader(),
|
context.getEnvironment(), context.getClassLoader(),
|
||||||
context.getResourceLoader())) {
|
context.getResourceLoader());
|
||||||
return ConditionOutcome.noMatch("Template from "
|
if (provider != null) {
|
||||||
+ availabilityProvider + " found for error view");
|
return ConditionOutcome
|
||||||
|
.noMatch("Template from " + provider + " found for error view");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return ConditionOutcome.match("No error template view detected");
|
return ConditionOutcome.match("No error template view detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2016 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.template;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.core.io.ResourceLoader;
|
||||||
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.times;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link TemplateAvailabilityProviders}.
|
||||||
|
*
|
||||||
|
* @author Phillip Webb
|
||||||
|
*/
|
||||||
|
public class TemplateAvailabilityProvidersTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
|
private TemplateAvailabilityProviders providers;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TemplateAvailabilityProvider provider;
|
||||||
|
|
||||||
|
private String view = "view";
|
||||||
|
|
||||||
|
private ClassLoader classLoader = getClass().getClassLoader();
|
||||||
|
|
||||||
|
private MockEnvironment environment = new MockEnvironment();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private ResourceLoader resourceLoader;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
this.providers = new TemplateAvailabilityProviders(
|
||||||
|
Collections.singleton(this.provider));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWhenApplicationContextIsNullShouldThrowException()
|
||||||
|
throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("ClassLoader must not be null");
|
||||||
|
new TemplateAvailabilityProviders((ApplicationContext) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWhenUsingApplicationContextShouldLoadProviders() throws Exception {
|
||||||
|
ApplicationContext applicationContext = mock(ApplicationContext.class);
|
||||||
|
given(applicationContext.getClassLoader()).willReturn(this.classLoader);
|
||||||
|
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(
|
||||||
|
applicationContext);
|
||||||
|
assertThat(providers.getProviders()).isNotEmpty();
|
||||||
|
verify(applicationContext).getClassLoader();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWhenClassLoaderIsNullShouldThrowException() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("ClassLoader must not be null");
|
||||||
|
new TemplateAvailabilityProviders((ClassLoader) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWhenUsingClassLoaderShouldLoadProviders() throws Exception {
|
||||||
|
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(
|
||||||
|
this.classLoader);
|
||||||
|
assertThat(providers.getProviders()).isNotEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWhenProvidersIsNullShouldThrowException() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("Providers must not be null");
|
||||||
|
new TemplateAvailabilityProviders(
|
||||||
|
(Collection<TemplateAvailabilityProvider>) null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createWhenUsingProvidersShouldUseProviders() throws Exception {
|
||||||
|
TemplateAvailabilityProviders providers = new TemplateAvailabilityProviders(
|
||||||
|
Collections.singleton(this.provider));
|
||||||
|
assertThat(providers.getProviders()).containsOnly(this.provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderWhenApplicationContextIsNullShouldThrowException()
|
||||||
|
throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("ApplicationContext must not be null");
|
||||||
|
this.providers.getProvider(this.view, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderWhenViewIsNullShouldThrowException() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("View must not be null");
|
||||||
|
this.providers.getProvider(null, this.environment, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderWhenEnvironmentIsNullShouldThrowException() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("Environment must not be null");
|
||||||
|
this.providers.getProvider(this.view, null, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderWhenClassLoaderIsNullShouldThrowException() throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("ClassLoader must not be null");
|
||||||
|
this.providers.getProvider(this.view, this.environment, null,
|
||||||
|
this.resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderWhenResourceLoaderIsNullShouldThrowException()
|
||||||
|
throws Exception {
|
||||||
|
this.thrown.expect(IllegalArgumentException.class);
|
||||||
|
this.thrown.expectMessage("ResourceLoader must not be null");
|
||||||
|
this.providers.getProvider(this.view, this.environment, this.classLoader, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderWhenNoneMatchShouldReturnNull() throws Exception {
|
||||||
|
TemplateAvailabilityProvider found = this.providers.getProvider(this.view,
|
||||||
|
this.environment, this.classLoader, this.resourceLoader);
|
||||||
|
assertThat(found).isNull();
|
||||||
|
verify(this.provider).isTemplateAvailable(this.view, this.environment,
|
||||||
|
this.classLoader, this.resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderWhenMatchShouldReturnProvider() throws Exception {
|
||||||
|
given(this.provider.isTemplateAvailable(this.view, this.environment,
|
||||||
|
this.classLoader, this.resourceLoader)).willReturn(true);
|
||||||
|
TemplateAvailabilityProvider found = this.providers.getProvider(this.view,
|
||||||
|
this.environment, this.classLoader, this.resourceLoader);
|
||||||
|
assertThat(found).isSameAs(this.provider);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderShouldCacheMatchResult() throws Exception {
|
||||||
|
given(this.provider.isTemplateAvailable(this.view, this.environment,
|
||||||
|
this.classLoader, this.resourceLoader)).willReturn(true);
|
||||||
|
this.providers.getProvider(this.view, this.environment, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
this.providers.getProvider(this.view, this.environment, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
verify(this.provider, times(1)).isTemplateAvailable(this.view, this.environment,
|
||||||
|
this.classLoader, this.resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProviderShouldCacheNoMatchResult() throws Exception {
|
||||||
|
this.providers.getProvider(this.view, this.environment, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
this.providers.getProvider(this.view, this.environment, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
verify(this.provider, times(1)).isTemplateAvailable(this.view, this.environment,
|
||||||
|
this.classLoader, this.resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getProvderWhenCacheDisabledShouldNotUseCache() throws Exception {
|
||||||
|
given(this.provider.isTemplateAvailable(this.view, this.environment,
|
||||||
|
this.classLoader, this.resourceLoader)).willReturn(true);
|
||||||
|
this.environment.setProperty("spring.template.provider.cache", "false");
|
||||||
|
this.providers.getProvider(this.view, this.environment, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
this.providers.getProvider(this.view, this.environment, this.classLoader,
|
||||||
|
this.resourceLoader);
|
||||||
|
verify(this.provider, times(2)).isTemplateAvailable(this.view, this.environment,
|
||||||
|
this.classLoader, this.resourceLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,7 +18,6 @@ package org.springframework.boot.autoconfigure.web;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -31,6 +30,7 @@ import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.template.TemplateAvailabilityProviders;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.core.Ordered;
|
import org.springframework.core.Ordered;
|
||||||
|
@ -78,8 +78,8 @@ public class DefaultErrorViewResolverTests {
|
||||||
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||||
applicationContext.refresh();
|
applicationContext.refresh();
|
||||||
this.resourceProperties = new ResourceProperties();
|
this.resourceProperties = new ResourceProperties();
|
||||||
List<TemplateAvailabilityProvider> templateAvailabilityProviders = Collections
|
TemplateAvailabilityProviders templateAvailabilityProviders = new TestTemplateAvailabilityProviders(
|
||||||
.singletonList(this.templateAvailabilityProvider);
|
this.templateAvailabilityProvider);
|
||||||
this.resolver = new DefaultErrorViewResolver(applicationContext,
|
this.resolver = new DefaultErrorViewResolver(applicationContext,
|
||||||
this.resourceProperties, templateAvailabilityProviders);
|
this.resourceProperties, templateAvailabilityProviders);
|
||||||
}
|
}
|
||||||
|
@ -221,4 +221,13 @@ public class DefaultErrorViewResolverTests {
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TestTemplateAvailabilityProviders
|
||||||
|
extends TemplateAvailabilityProviders {
|
||||||
|
|
||||||
|
TestTemplateAvailabilityProviders(TemplateAvailabilityProvider provider) {
|
||||||
|
super(Collections.singletonList(provider));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro
|
||||||
properties.put("server.session.persistent", "true");
|
properties.put("server.session.persistent", "true");
|
||||||
properties.put("spring.h2.console.enabled", "true");
|
properties.put("spring.h2.console.enabled", "true");
|
||||||
properties.put("spring.resources.cache-period", "0");
|
properties.put("spring.resources.cache-period", "0");
|
||||||
|
properties.put("spring.template.provider.cache", "false");
|
||||||
PROPERTIES = Collections.unmodifiableMap(properties);
|
PROPERTIES = Collections.unmodifiableMap(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue