diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java index bd73623aff2..c4a11ba4ba1 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/view/script/ScriptTemplateView.java @@ -18,8 +18,6 @@ package org.springframework.web.servlet.view.script; import java.io.IOException; import java.io.InputStreamReader; -import java.net.URL; -import java.net.URLClassLoader; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; @@ -40,7 +38,6 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.core.NamedThreadLocal; -import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.scripting.support.StandardScriptEvalException; @@ -96,7 +93,7 @@ public class ScriptTemplateView extends AbstractUrlBasedView { private Charset charset; - private String resourceLoaderPath; + private String[] resourceLoaderPaths; private ResourceLoader resourceLoader; @@ -184,7 +181,16 @@ public class ScriptTemplateView extends AbstractUrlBasedView { * See {@link ScriptTemplateConfigurer#setResourceLoaderPath(String)} documentation. */ public void setResourceLoaderPath(String resourceLoaderPath) { - this.resourceLoaderPath = resourceLoaderPath; + String[] paths = StringUtils.commaDelimitedListToStringArray(resourceLoaderPath); + this.resourceLoaderPaths = new String[paths.length + 1]; + this.resourceLoaderPaths[0] = ""; + for (int i = 0; i < paths.length; i++) { + String path = paths[i]; + if (!path.endsWith("/") && !path.endsWith(":")) { + path = path + "/"; + } + this.resourceLoaderPaths[i + 1] = path; + } } @@ -214,12 +220,12 @@ public class ScriptTemplateView extends AbstractUrlBasedView { if (this.charset == null) { this.charset = (viewConfig.getCharset() != null ? viewConfig.getCharset() : DEFAULT_CHARSET); } - if (this.resourceLoaderPath == null) { - this.resourceLoaderPath = (viewConfig.getResourceLoaderPath() != null ? - viewConfig.getResourceLoaderPath() : DEFAULT_RESOURCE_LOADER_PATH); + if (this.resourceLoaderPaths == null) { + String resourceLoaderPath = viewConfig.getResourceLoaderPath(); + setResourceLoaderPath(resourceLoaderPath == null ? DEFAULT_RESOURCE_LOADER_PATH : resourceLoaderPath); } if (this.resourceLoader == null) { - this.resourceLoader = new DefaultResourceLoader(createClassLoader()); + this.resourceLoader = getApplicationContext(); } if (this.sharedEngine == null && viewConfig.isSharedEngine() != null) { this.sharedEngine = viewConfig.isSharedEngine(); @@ -282,10 +288,7 @@ public class ScriptTemplateView extends AbstractUrlBasedView { if (!ObjectUtils.isEmpty(this.scripts)) { try { for (String script : this.scripts) { - Resource resource = this.resourceLoader.getResource(script); - if (!resource.exists()) { - throw new IllegalStateException("Script resource [" + script + "] not found"); - } + Resource resource = getResource(script); engine.eval(new InputStreamReader(resource.getInputStream())); } } @@ -295,26 +298,14 @@ public class ScriptTemplateView extends AbstractUrlBasedView { } } - protected ClassLoader createClassLoader() { - String[] paths = StringUtils.commaDelimitedListToStringArray(this.resourceLoaderPath); - List urls = new ArrayList(); - try { - for (String path : paths) { - Resource[] resources = getApplicationContext().getResources(path); - if (resources.length > 0) { - for (Resource resource : resources) { - if (resource.exists()) { - urls.add(resource.getURL()); - } - } - } + protected Resource getResource(String location) { + for (String path : this.resourceLoaderPaths) { + Resource resource = this.resourceLoader.getResource(path + location); + if (resource.exists()) { + return resource; } } - catch (IOException ex) { - throw new IllegalStateException("Cannot create class loader: " + ex.getMessage()); - } - ClassLoader classLoader = getApplicationContext().getClassLoader(); - return (urls.size() > 0 ? new URLClassLoader(urls.toArray(new URL[urls.size()]), classLoader) : classLoader); + throw new IllegalStateException("Resource [" + location + "] not found"); } protected ScriptTemplateConfig autodetectViewConfig() throws BeansException { @@ -329,7 +320,6 @@ public class ScriptTemplateView extends AbstractUrlBasedView { } } - @Override protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { super.prepareResponse(request, response); @@ -365,7 +355,7 @@ public class ScriptTemplateView extends AbstractUrlBasedView { } protected String getTemplate(String path) throws IOException { - Resource resource = this.resourceLoader.getResource(path); + Resource resource = getResource(path); InputStreamReader reader = new InputStreamReader(resource.getInputStream(), this.charset); return FileCopyUtils.copyToString(reader); } diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script/ScriptTemplateViewTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script/ScriptTemplateViewTests.java index f72c0afd115..af4e8251d52 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script/ScriptTemplateViewTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/view/script/ScriptTemplateViewTests.java @@ -16,10 +16,8 @@ package org.springframework.web.servlet.view.script; -import java.net.URLClassLoader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,8 +27,6 @@ import java.util.concurrent.Future; import javax.script.Invocable; import javax.script.ScriptEngine; -import org.hamcrest.Matchers; - import org.junit.Before; import org.junit.Test; @@ -62,8 +58,6 @@ public class ScriptTemplateViewTests { private StaticWebApplicationContext wac; - private static final String RESOURCE_LOADER_PATH = "classpath:org/springframework/web/servlet/view/script/"; - @Before public void setup() { @@ -71,7 +65,6 @@ public class ScriptTemplateViewTests { this.wac = new StaticWebApplicationContext(); this.wac.getBeanFactory().registerSingleton("scriptTemplateConfigurer", this.configurer); this.view = new ScriptTemplateView(); - this.view.setUrl(RESOURCE_LOADER_PATH + "empty.txt"); } @Test @@ -211,26 +204,35 @@ public class ScriptTemplateViewTests { fail(); } - @Test - @SuppressWarnings("resource") - public void parentLoader() { - this.view.setEngine(mock(InvocableScriptEngine.class)); + @Test // SPR-14210 + public void resourceLoaderPath() throws Exception { + MockServletContext servletContext = new MockServletContext(); + this.wac.setServletContext(servletContext); + this.wac.refresh(); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.wac); + MockHttpServletResponse response = new MockHttpServletResponse(); + Map model = new HashMap(); + InvocableScriptEngine engine = mock(InvocableScriptEngine.class); + when(engine.invokeFunction(any(), any(), any(), any())).thenReturn("foo"); + this.view.setEngine(engine); this.view.setRenderFunction("render"); - this.view.setResourceLoaderPath(RESOURCE_LOADER_PATH); this.view.setApplicationContext(this.wac); - ClassLoader classLoader = this.view.createClassLoader(); - assertNotNull(classLoader); - URLClassLoader urlClassLoader = (URLClassLoader) classLoader; - assertThat(Arrays.asList(urlClassLoader.getURLs()), Matchers.hasSize(1)); - assertThat(Arrays.asList(urlClassLoader.getURLs()).get(0).toString(), - Matchers.endsWith("org/springframework/web/servlet/view/script/")); - this.view.setResourceLoaderPath(RESOURCE_LOADER_PATH + ",classpath:org/springframework/web/servlet/view/"); - classLoader = this.view.createClassLoader(); - assertNotNull(classLoader); - urlClassLoader = (URLClassLoader) classLoader; - assertThat(Arrays.asList(urlClassLoader.getURLs()), Matchers.hasSize(2)); - assertThat(Arrays.asList(urlClassLoader.getURLs()).get(0).toString(), Matchers.endsWith("org/springframework/web/servlet/view/script/")); - assertThat(Arrays.asList(urlClassLoader.getURLs()).get(1).toString(), Matchers.endsWith("org/springframework/web/servlet/view/")); + this.view.setUrl("org/springframework/web/servlet/view/script/empty.txt"); + this.view.render(model, request, response); + assertEquals("foo", response.getContentAsString()); + + response = new MockHttpServletResponse(); + this.view.setResourceLoaderPath("classpath:org/springframework/web/servlet/view/script/"); + this.view.setUrl("empty.txt"); + this.view.render(model, request, response); + assertEquals("foo", response.getContentAsString()); + + response = new MockHttpServletResponse(); + this.view.setResourceLoaderPath("classpath:org/springframework/web/servlet/view/script"); + this.view.setUrl("empty.txt"); + this.view.render(model, request, response); + assertEquals("foo", response.getContentAsString()); } @Test // SPR-13379 @@ -244,7 +246,8 @@ public class ScriptTemplateViewTests { Map model = new HashMap(); this.view.setEngine(mock(InvocableScriptEngine.class)); this.view.setRenderFunction("render"); - this.view.setResourceLoaderPath(RESOURCE_LOADER_PATH); + this.view.setResourceLoaderPath("classpath:org/springframework/web/servlet/view/script/"); + this.view.setUrl("empty.txt"); this.view.setApplicationContext(this.wac); this.view.render(model, request, response);