diff --git a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java index c58ea9aba4335bcb59128afbec14124b60bda552..a81f6c3818ebcbbbc7e9a49098d86a1ed84e4478 100644 --- a/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java +++ b/spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2015 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. @@ -60,7 +60,7 @@ public abstract class AbstractFileResolvingResource extends AbstractResource { protected File getFileForLastModifiedCheck() throws IOException { URL url = getURL(); if (ResourceUtils.isJarURL(url)) { - URL actualUrl = ResourceUtils.extractJarFileURL(url); + URL actualUrl = ResourceUtils.extractArchiveURL(url); if (actualUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { return VfsResourceDelegate.getResource(actualUrl).getFile(); } diff --git a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java index 4962e503fa1b775d8eecbd3937fa3d7515dbe04a..3ea92707e130838c04242953e3883fc23662c034 100644 --- a/spring-core/src/main/java/org/springframework/util/ResourceUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ResourceUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 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. @@ -57,9 +57,12 @@ public abstract class ResourceUtils { /** URL prefix for loading from the file system: "file:" */ public static final String FILE_URL_PREFIX = "file:"; - /** URL prefix for loading from the file system: "jar:" */ + /** URL prefix for loading from a jar file: "jar:" */ public static final String JAR_URL_PREFIX = "jar:"; + /** URL prefix for loading from a war file on Tomcat: "war:" */ + public static final String WAR_URL_PREFIX = "war:"; + /** URL protocol for a file in the file system: "file" */ public static final String URL_PROTOCOL_FILE = "file"; @@ -87,6 +90,9 @@ public abstract class ResourceUtils { /** Separator between JAR URL and file path within the JAR: "!/" */ public static final String JAR_URL_SEPARATOR = "!/"; + /** Special separator between WAR URL and jar part on Tomcat */ + public static final String WAR_URL_SEPARATOR = "*/"; + /** * Return whether the given resource location is a URL: @@ -319,6 +325,34 @@ public abstract class ResourceUtils { } } + /** + * Extract the URL for the outermost archive from the given jar/war URL + * (which may point to a resource in a jar file or to a jar file itself). + *
In the case of a jar file nested within a war file, this will return + * a URL to the war file since that is the one resolvable in the file system. + * @param jarUrl the original URL + * @return the URL for the actual jar file + * @throws MalformedURLException if no valid jar file URL could be extracted + * @since 4.1.8 + * @see #extractJarFileURL(URL) + */ + public static URL extractArchiveURL(URL jarUrl) throws MalformedURLException { + String urlFile = jarUrl.getFile(); + + int endIndex = urlFile.indexOf(WAR_URL_SEPARATOR); + if (endIndex != -1) { + // Tomcat's "jar:war:file:...mywar.war*/WEB-INF/lib/myjar.jar!/myentry.txt" + String warFile = urlFile.substring(0, endIndex); + int startIndex = warFile.indexOf(WAR_URL_PREFIX); + if (startIndex != -1) { + return new URL(warFile.substring(startIndex + WAR_URL_PREFIX.length())); + } + } + + // Regular "jar:file:...myjar.jar!/myentry.txt" + return extractJarFileURL(jarUrl); + } + /** * Create a URI instance for the given URL, * replacing spaces with "%20" URI encoding first. diff --git a/spring-core/src/test/java/org/springframework/util/ResourceUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ResourceUtilsTests.java index 7129e8d23ca0b0f292fb5d9594d5bc35e861d9ac..d70b38311426d67d999c19a17489c65bc863e5b2 100644 --- a/spring-core/src/test/java/org/springframework/util/ResourceUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/ResourceUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -21,22 +21,27 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; -import junit.framework.TestCase; +import org.junit.Test; + +import static org.junit.Assert.*; /** * @author Juergen Hoeller */ -public class ResourceUtilsTests extends TestCase { +public class ResourceUtilsTests { - public void testIsJarURL() throws Exception { + @Test + public void isJarURL() throws Exception { assertTrue(ResourceUtils.isJarURL(new URL("jar:file:myjar.jar!/mypath"))); assertTrue(ResourceUtils.isJarURL(new URL(null, "zip:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); assertTrue(ResourceUtils.isJarURL(new URL(null, "wsjar:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertTrue(ResourceUtils.isJarURL(new URL(null, "jar:war:file:mywar.war*/myjar.jar!/mypath", new DummyURLStreamHandler()))); assertFalse(ResourceUtils.isJarURL(new URL("file:myjar.jar"))); assertFalse(ResourceUtils.isJarURL(new URL("http:myserver/myjar.jar"))); } - public void testExtractJarFileURL() throws Exception { + @Test + public void extractJarFileURL() throws Exception { assertEquals(new URL("file:myjar.jar"), ResourceUtils.extractJarFileURL(new URL("jar:file:myjar.jar!/mypath"))); assertEquals(new URL("file:/myjar.jar"), @@ -45,14 +50,40 @@ public class ResourceUtilsTests extends TestCase { ResourceUtils.extractJarFileURL(new URL(null, "zip:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); assertEquals(new URL("file:myjar.jar"), ResourceUtils.extractJarFileURL(new URL(null, "wsjar:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractJarFileURL(new URL("file:myjar.jar"))); assertEquals(new URL("file:myjar.jar"), ResourceUtils.extractJarFileURL(new URL("jar:file:myjar.jar!/"))); assertEquals(new URL("file:myjar.jar"), ResourceUtils.extractJarFileURL(new URL(null, "zip:file:myjar.jar!/", new DummyURLStreamHandler()))); assertEquals(new URL("file:myjar.jar"), ResourceUtils.extractJarFileURL(new URL(null, "wsjar:file:myjar.jar!/", new DummyURLStreamHandler()))); + } + + @Test + public void extractArchiveURL() throws Exception { assertEquals(new URL("file:myjar.jar"), - ResourceUtils.extractJarFileURL(new URL("file:myjar.jar"))); + ResourceUtils.extractArchiveURL(new URL("jar:file:myjar.jar!/mypath"))); + assertEquals(new URL("file:/myjar.jar"), + ResourceUtils.extractArchiveURL(new URL(null, "jar:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractArchiveURL(new URL(null, "zip:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractArchiveURL(new URL(null, "wsjar:file:myjar.jar!/mypath", new DummyURLStreamHandler()))); + assertEquals(new URL("file:mywar.war"), + ResourceUtils.extractArchiveURL(new URL(null, "jar:war:file:mywar.war*/myjar.jar!/mypath", new DummyURLStreamHandler()))); + + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractArchiveURL(new URL("file:myjar.jar"))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractArchiveURL(new URL("jar:file:myjar.jar!/"))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractArchiveURL(new URL(null, "zip:file:myjar.jar!/", new DummyURLStreamHandler()))); + assertEquals(new URL("file:myjar.jar"), + ResourceUtils.extractArchiveURL(new URL(null, "wsjar:file:myjar.jar!/", new DummyURLStreamHandler()))); + assertEquals(new URL("file:mywar.war"), + ResourceUtils.extractArchiveURL(new URL(null, "jar:war:file:mywar.war*/myjar.jar!/", new DummyURLStreamHandler()))); }