From 0f3b959686435e6ba9dba57ba936cd0f58453440 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 17 Dec 2014 23:10:35 -0800 Subject: [PATCH] Scan full classpath with /templates checks Update template auto configurations to search for template folders in the entire classpath rather than just the root jar. Fixes gh-2184 --- .../FreeMarkerAutoConfiguration.java | 23 +++-- .../GroovyTemplateAutoConfiguration.java | 20 ++--- .../template/TemplateLocation.java | 84 +++++++++++++++++++ .../thymeleaf/ThymeleafAutoConfiguration.java | 20 ++--- .../velocity/VelocityAutoConfiguration.java | 19 +++-- 5 files changed, 125 insertions(+), 41 deletions(-) create mode 100644 spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateLocation.java diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java index a63dd230949..241765fe5f2 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/freemarker/FreeMarkerAutoConfiguration.java @@ -31,13 +31,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.template.TemplateLocation; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.ui.freemarker.FreeMarkerConfigurationFactory; import org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean; import org.springframework.util.Assert; @@ -60,7 +59,7 @@ import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver; public class FreeMarkerAutoConfiguration { @Autowired - private final ResourceLoader resourceLoader = new DefaultResourceLoader(); + private ApplicationContext applicationContext; @Autowired private FreeMarkerProperties properties; @@ -68,18 +67,18 @@ public class FreeMarkerAutoConfiguration { @PostConstruct public void checkTemplateLocationExists() { if (this.properties.isCheckTemplateLocation()) { - Resource templatePathResource = null; - List resources = new ArrayList(); + TemplateLocation templatePathLocation = null; + List locations = new ArrayList(); for (String templateLoaderPath : this.properties.getTemplateLoaderPath()) { - Resource resource = this.resourceLoader.getResource(templateLoaderPath); - resources.add(resource); - if (resource.exists()) { - templatePathResource = resource; + TemplateLocation location = new TemplateLocation(templateLoaderPath); + locations.add(location); + if (location.exists(this.applicationContext)) { + templatePathLocation = location; break; } } - Assert.notNull(templatePathResource, "Cannot find template location(s): " - + resources + " (please add some templates, " + Assert.notNull(templatePathLocation, "Cannot find template location(s): " + + locations + " (please add some templates, " + "check your FreeMarker configuration, or set " + "spring.freemarker.checkTemplateLocation=false)"); } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java index f37f6bd1b41..e1243533010 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/groovy/template/GroovyTemplateAutoConfiguration.java @@ -30,16 +30,15 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.template.TemplateLocation; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.core.Ordered; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.springframework.web.servlet.view.UrlBasedViewResolver; import org.springframework.web.servlet.view.groovy.GroovyMarkupConfig; @@ -68,7 +67,7 @@ public class GroovyTemplateAutoConfiguration { public static class GroovyMarkupConfiguration { @Autowired - private final ResourceLoader resourceLoader = new DefaultResourceLoader(); + private ApplicationContext applicationContext; @Autowired private GroovyTemplateProperties properties; @@ -79,12 +78,13 @@ public class GroovyTemplateAutoConfiguration { @PostConstruct public void checkTemplateLocationExists() { if (this.properties.isCheckTemplateLocation() && !isUsingGroovyAllJar()) { - Resource resource = this.resourceLoader.getResource(this.properties - .getPrefix()); - Assert.state(resource.exists(), "Cannot find template location: " - + resource + " (please add some templates, " - + "check your Groovy configuration, or set " - + "spring.groovy.template.check-template-location=false)"); + TemplateLocation location = new TemplateLocation( + this.properties.getPrefix()); + Assert.state(location.exists(this.applicationContext), + "Cannot find template location: " + location + + " (please add some templates, check your Groovy " + + "configuration, or set spring.groovy.template." + + "check-template-location=false)"); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateLocation.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateLocation.java new file mode 100644 index 00000000000..5d7e703633d --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/template/TemplateLocation.java @@ -0,0 +1,84 @@ +/* + * Copyright 2012-2014 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.io.IOException; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.core.io.support.ResourcePatternResolver; +import org.springframework.util.Assert; + +/** + * Contains a location that templates can be loaded from. + * + * @author Phillip Webb + * @since 1.2.1 + */ +public class TemplateLocation { + + private final String path; + + public TemplateLocation(String path) { + Assert.notNull(path, "Path must not be null"); + this.path = path; + } + + /** + * Determine if this template location exists using the specified + * {@link ResourcePatternResolver}. + * @param resolver the resolver used to test if the location exists + * @return {@code true} if the location exists. + */ + public boolean exists(ResourcePatternResolver resolver) { + Assert.notNull(resolver, "Resolver must not be null"); + if (resolver.getResource(this.path).exists()) { + return true; + } + try { + if (anyExists(resolver)) { + return true; + } + } + catch (IOException ex) { + } + return false; + } + + private boolean anyExists(ResourcePatternResolver resolver) throws IOException { + String searchPath = this.path; + if (searchPath.startsWith(ResourceLoader.CLASSPATH_URL_PREFIX)) { + searchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + + searchPath.substring(ResourceLoader.CLASSPATH_URL_PREFIX.length()); + } + if (this.path.startsWith(ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX)) { + Resource[] resources = resolver.getResources(this.path); + for (Resource resource : resources) { + if (resource.exists()) { + return true; + } + } + } + return false; + } + + @Override + public String toString() { + return this.path; + } + +} 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 f0cc34e1460..c9a32d7cc98 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 @@ -31,14 +31,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.template.TemplateLocation; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.util.Assert; import org.thymeleaf.dialect.IDialect; import org.thymeleaf.extras.conditionalcomments.dialect.ConditionalCommentsDialect; @@ -72,17 +71,18 @@ public class ThymeleafAutoConfiguration { private ThymeleafProperties properties; @Autowired - private final ResourceLoader resourceLoader = new DefaultResourceLoader(); + private ApplicationContext applicationContext; @PostConstruct public void checkTemplateLocationExists() { - Boolean checkTemplateLocation = this.properties.isCheckTemplateLocation(); + boolean checkTemplateLocation = this.properties.isCheckTemplateLocation(); if (checkTemplateLocation) { - Resource resource = this.resourceLoader.getResource(this.properties - .getPrefix()); - Assert.state(resource.exists(), "Cannot find template location: " - + resource + " (please add some templates " - + "or check your Thymeleaf configuration)"); + TemplateLocation location = new TemplateLocation( + this.properties.getPrefix()); + Assert.state(location.exists(this.applicationContext), + "Cannot find template location: " + location + + " (please add some templates or check " + + "your Thymeleaf configuration)"); } } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java index e67f42e7cfc..cf2b628995c 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/velocity/VelocityAutoConfiguration.java @@ -32,13 +32,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.template.TemplateLocation; import org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.DefaultResourceLoader; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; import org.springframework.ui.velocity.VelocityEngineFactory; import org.springframework.ui.velocity.VelocityEngineFactoryBean; import org.springframework.util.Assert; @@ -59,7 +58,7 @@ import org.springframework.web.servlet.view.velocity.VelocityViewResolver; public class VelocityAutoConfiguration { @Autowired - private final ResourceLoader resourceLoader = new DefaultResourceLoader(); + private ApplicationContext applicationContext; @Autowired private VelocityProperties properties; @@ -67,11 +66,13 @@ public class VelocityAutoConfiguration { @PostConstruct public void checkTemplateLocationExists() { if (this.properties.isCheckTemplateLocation()) { - Resource resource = this.resourceLoader.getResource(this.properties - .getResourceLoaderPath()); - Assert.state(resource.exists(), "Cannot find template location: " + resource - + " (please add some templates, check your Velocity configuration, " - + "or set spring.velocity.checkTemplateLocation=false)"); + TemplateLocation location = new TemplateLocation( + this.properties.getResourceLoaderPath()); + Assert.state(location.exists(this.applicationContext), + "Cannot find template location: " + location + + " (please add some templates, check your Velocity " + + "configuration, or set spring.velocity." + + "checkTemplateLocation=false)"); } }