diff --git a/guava-tests/test/com/google/common/reflect/ClassPathTest.java b/guava-tests/test/com/google/common/reflect/ClassPathTest.java index 8a6bf0fa04ad..e21d57e41fe4 100644 --- a/guava-tests/test/com/google/common/reflect/ClassPathTest.java +++ b/guava-tests/test/com/google/common/reflect/ClassPathTest.java @@ -39,7 +39,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URI; +import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; @@ -177,7 +177,7 @@ public void testClassPathEntries_URLClassLoader_noParent() throws Exception { URL url2 = new URL("file:/b"); URLClassLoader classloader = new URLClassLoader(new URL[] {url1, url2}, null); assertEquals( - ImmutableMap.of(url1.toURI(), classloader, url2.toURI(), classloader), + ImmutableMap.of(new File("/a"), classloader, new File("/b"), classloader), ClassPath.getClassPathEntries(classloader)); } @@ -186,16 +186,16 @@ public void testClassPathEntries_URLClassLoader_withParent() throws Exception { URL url2 = new URL("file:/b"); URLClassLoader parent = new URLClassLoader(new URL[] {url1}, null); URLClassLoader child = new URLClassLoader(new URL[] {url2}, parent) {}; - ImmutableMap classPathEntries = ClassPath.getClassPathEntries(child); - assertEquals(ImmutableMap.of(url1.toURI(), parent, url2.toURI(), child), classPathEntries); - assertThat(classPathEntries.keySet()).containsExactly(url1.toURI(), url2.toURI()).inOrder(); + ImmutableMap classPathEntries = ClassPath.getClassPathEntries(child); + assertEquals(ImmutableMap.of(new File("/a"), parent, new File("/b"), child), classPathEntries); + assertThat(classPathEntries.keySet()).containsExactly(new File("/a"), new File("/b")).inOrder(); } public void testClassPathEntries_duplicateUri_parentWins() throws Exception { URL url = new URL("file:/a"); URLClassLoader parent = new URLClassLoader(new URL[] {url}, null); URLClassLoader child = new URLClassLoader(new URL[] {url}, parent) {}; - assertEquals(ImmutableMap.of(url.toURI(), parent), ClassPath.getClassPathEntries(child)); + assertEquals(ImmutableMap.of(new File("/a"), parent), ClassPath.getClassPathEntries(child)); } public void testClassPathEntries_notURLClassLoader_noParent() { @@ -206,7 +206,7 @@ public void testClassPathEntries_notURLClassLoader_withParent() throws Exception URL url = new URL("file:/a"); URLClassLoader parent = new URLClassLoader(new URL[] {url}, null); assertEquals( - ImmutableMap.of(url.toURI(), parent), + ImmutableMap.of(new File("/a"), parent), ClassPath.getClassPathEntries(new ClassLoader(parent) {})); } @@ -216,7 +216,7 @@ public void testClassPathEntries_notURLClassLoader_withParentAndGrandParent() th URLClassLoader grandParent = new URLClassLoader(new URL[] {url1}, null); URLClassLoader parent = new URLClassLoader(new URL[] {url2}, grandParent); assertEquals( - ImmutableMap.of(url1.toURI(), grandParent, url2.toURI(), parent), + ImmutableMap.of(new File("/a"), grandParent, new File("/b"), parent), ClassPath.getClassPathEntries(new ClassLoader(parent) {})); } @@ -225,7 +225,7 @@ public void testClassPathEntries_notURLClassLoader_withGrandParent() throws Exce URLClassLoader grandParent = new URLClassLoader(new URL[] {url}, null); ClassLoader parent = new ClassLoader(grandParent) {}; assertEquals( - ImmutableMap.of(url.toURI(), grandParent), + ImmutableMap.of(new File("/a"), grandParent), ClassPath.getClassPathEntries(new ClassLoader(parent) {})); } @@ -234,7 +234,7 @@ public void testScan_classPathCycle() throws IOException { try { writeSelfReferencingJarFile(jarFile, "test.txt"); ClassPath.Scanner scanner = new ClassPath.Scanner(); - scanner.scan(jarFile.toURI(), ClassPathTest.class.getClassLoader()); + scanner.scan(jarFile, ClassPathTest.class.getClassLoader()); assertEquals(1, scanner.getResources().size()); } finally { jarFile.delete(); @@ -260,16 +260,20 @@ public void testScanFromFile_notJarFile() throws IOException { assertThat(scanner.getResources()).isEmpty(); } - public void testGetClassPathEntry() throws URISyntaxException { - assertEquals(URI.create("file:/usr/test/dep.jar"), + public void testGetClassPathEntry() throws MalformedURLException, URISyntaxException { + assertEquals(new File("/usr/test/dep.jar").toURI(), ClassPath.Scanner.getClassPathEntry( - new File("/home/build/outer.jar"), "file:/usr/test/dep.jar")); - assertEquals(URI.create("file:/home/build/a.jar"), - ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "a.jar")); - assertEquals(URI.create("file:/home/build/x/y/z"), - ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z")); - assertEquals(URI.create("file:/home/build/x/y/z.jar"), - ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z.jar")); + new File("/home/build/outer.jar"), "file:/usr/test/dep.jar").toURI()); + assertEquals(new File("/home/build/a.jar").toURI(), + ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "a.jar").toURI()); + assertEquals(new File("/home/build/x/y/z").toURI(), + ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z").toURI()); + assertEquals(new File("/home/build/x/y/z.jar").toURI(), + ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "x/y/z.jar") + .toURI()); + assertEquals("/home/build/x y.jar", + ClassPath.Scanner.getClassPathEntry(new File("/home/build/outer.jar"), "x y.jar") + .getFile()); } public void testGetClassPathFromManifest_nullManifest() { @@ -290,17 +294,24 @@ public void testGetClassPathFromManifest_emptyClassPath() throws IOException { public void testGetClassPathFromManifest_badClassPath() throws IOException { File jarFile = new File("base.jar"); - Manifest manifest = manifestClasspath("an_invalid^path"); + Manifest manifest = manifestClasspath("nosuchscheme:an_invalid^path"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) .isEmpty(); } + public void testGetClassPathFromManifest_pathWithStrangeCharacter() throws IOException { + File jarFile = new File("base/some.jar"); + Manifest manifest = manifestClasspath("file:the^file.jar"); + assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) + .containsExactly(fullpath("base/the^file.jar")); + } + public void testGetClassPathFromManifest_relativeDirectory() throws IOException { File jarFile = new File("base/some.jar"); // with/relative/directory is the Class-Path value in the mf file. Manifest manifest = manifestClasspath("with/relative/dir"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) - .containsExactly(new File("base/with/relative/dir").toURI()); + .containsExactly(fullpath("base/with/relative/dir")); } public void testGetClassPathFromManifest_relativeJar() throws IOException { @@ -308,7 +319,7 @@ public void testGetClassPathFromManifest_relativeJar() throws IOException { // with/relative/directory is the Class-Path value in the mf file. Manifest manifest = manifestClasspath("with/relative.jar"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) - .containsExactly(new File("base/with/relative.jar").toURI()); + .containsExactly(fullpath("base/with/relative.jar")); } public void testGetClassPathFromManifest_jarInCurrentDirectory() throws IOException { @@ -316,21 +327,21 @@ public void testGetClassPathFromManifest_jarInCurrentDirectory() throws IOExcept // with/relative/directory is the Class-Path value in the mf file. Manifest manifest = manifestClasspath("current.jar"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) - .containsExactly(new File("base/current.jar").toURI()); + .containsExactly(fullpath("base/current.jar")); } public void testGetClassPathFromManifest_absoluteDirectory() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath("file:/with/absolute/dir"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) - .containsExactly(new File("/with/absolute/dir").toURI()); + .containsExactly(fullpath("/with/absolute/dir")); } public void testGetClassPathFromManifest_absoluteJar() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath("file:/with/absolute.jar"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) - .containsExactly(new File("/with/absolute.jar").toURI()); + .containsExactly(fullpath("/with/absolute.jar")); } public void testGetClassPathFromManifest_multiplePaths() throws IOException { @@ -338,9 +349,9 @@ public void testGetClassPathFromManifest_multiplePaths() throws IOException { Manifest manifest = manifestClasspath("file:/with/absolute.jar relative.jar relative/dir"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) .containsExactly( - new File("/with/absolute.jar").toURI(), - new File("base/relative.jar").toURI(), - new File("base/relative/dir").toURI()) + fullpath("/with/absolute.jar"), + fullpath("base/relative.jar"), + fullpath("base/relative/dir")) .inOrder(); } @@ -348,14 +359,14 @@ public void testGetClassPathFromManifest_leadingBlanks() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath(" relative.jar"); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) - .containsExactly(new File("base/relative.jar").toURI()); + .containsExactly(fullpath("base/relative.jar")); } public void testGetClassPathFromManifest_trailingBlanks() throws IOException { File jarFile = new File("base/some.jar"); Manifest manifest = manifestClasspath("relative.jar "); assertThat(ClassPath.Scanner.getClassPathFromManifest(jarFile, manifest)) - .containsExactly(new File("base/relative.jar").toURI()); + .containsExactly(fullpath("base/relative.jar")); } public void testGetClassName() { @@ -456,4 +467,8 @@ private static Manifest manifest(String content) throws IOException { manifest.read(in); return manifest; } + + private static File fullpath(String path) { + return new File(new File(path).toURI()); + } } diff --git a/guava/src/com/google/common/reflect/ClassPath.java b/guava/src/com/google/common/reflect/ClassPath.java index cadb825965c2..8ee54cbd92a5 100644 --- a/guava/src/com/google/common/reflect/ClassPath.java +++ b/guava/src/com/google/common/reflect/ClassPath.java @@ -33,8 +33,7 @@ import java.io.File; import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; @@ -88,7 +87,7 @@ private ClassPath(ImmutableSet resources) { */ public static ClassPath from(ClassLoader classloader) throws IOException { Scanner scanner = new Scanner(); - for (Map.Entry entry : getClassPathEntries(classloader).entrySet()) { + for (Map.Entry entry : getClassPathEntries(classloader).entrySet()) { scanner.scan(entry.getKey(), entry.getValue()); } return new ClassPath(scanner.getResources()); @@ -275,9 +274,9 @@ public Class load() { } } - @VisibleForTesting static ImmutableMap getClassPathEntries( + @VisibleForTesting static ImmutableMap getClassPathEntries( ClassLoader classloader) { - LinkedHashMap entries = Maps.newLinkedHashMap(); + LinkedHashMap entries = Maps.newLinkedHashMap(); // Search parent first, since it's the order ClassLoader#loadClass() uses. ClassLoader parent = classloader.getParent(); if (parent != null) { @@ -286,14 +285,11 @@ public Class load() { if (classloader instanceof URLClassLoader) { URLClassLoader urlClassLoader = (URLClassLoader) classloader; for (URL entry : urlClassLoader.getURLs()) { - URI uri; - try { - uri = entry.toURI(); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - if (!entries.containsKey(uri)) { - entries.put(uri, classloader); + if (entry.getProtocol().equals("file")) { + File file = new File(entry.getFile()); + if (!entries.containsKey(file)) { + entries.put(file, classloader); + } } } } @@ -304,15 +300,15 @@ public Class load() { private final ImmutableSortedSet.Builder resources = new ImmutableSortedSet.Builder(Ordering.usingToString()); - private final Set scannedUris = Sets.newHashSet(); + private final Set scannedUris = Sets.newHashSet(); ImmutableSortedSet getResources() { return resources.build(); } - void scan(URI uri, ClassLoader classloader) throws IOException { - if (uri.getScheme().equals("file") && scannedUris.add(uri)) { - scanFrom(new File(uri), classloader); + void scan(File file, ClassLoader classloader) throws IOException { + if (scannedUris.add(file)) { + scanFrom(file, classloader); } } @@ -372,8 +368,8 @@ private void scanJar(File file, ClassLoader classloader) throws IOException { return; } try { - for (URI uri : getClassPathFromManifest(file, jarFile.getManifest())) { - scan(uri, classloader); + for (File path : getClassPathFromManifest(file, jarFile.getManifest())) { + scan(path, classloader); } Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { @@ -392,29 +388,32 @@ private void scanJar(File file, ClassLoader classloader) throws IOException { /** * Returns the class path URIs specified by the {@code Class-Path} manifest attribute, according - * to + * to + * * JAR File Specification. If {@code manifest} is null, it means the jar file has no * manifest, and an empty set will be returned. */ - @VisibleForTesting static ImmutableSet getClassPathFromManifest( + @VisibleForTesting static ImmutableSet getClassPathFromManifest( File jarFile, @Nullable Manifest manifest) { if (manifest == null) { return ImmutableSet.of(); } - ImmutableSet.Builder builder = ImmutableSet.builder(); + ImmutableSet.Builder builder = ImmutableSet.builder(); String classpathAttribute = manifest.getMainAttributes() .getValue(Attributes.Name.CLASS_PATH.toString()); if (classpathAttribute != null) { for (String path : CLASS_PATH_ATTRIBUTE_SEPARATOR.split(classpathAttribute)) { - URI uri; + URL url; try { - uri = getClassPathEntry(jarFile, path); - } catch (URISyntaxException e) { + url = getClassPathEntry(jarFile, path); + } catch (MalformedURLException e) { // Ignore bad entry logger.warning("Invalid Class-Path entry: " + path); continue; } - builder.add(uri); + if (url.getProtocol().equals("file")) { + builder.add(new File(url.getFile())); + } } } return builder.build(); @@ -422,18 +421,13 @@ private void scanJar(File file, ClassLoader classloader) throws IOException { /** * Returns the absolute uri of the Class-Path entry value as specified in - * + * * JAR File Specification. Even though the specification only talks about relative urls, * absolute urls are actually supported too (for example, in Maven surefire plugin). */ - @VisibleForTesting static URI getClassPathEntry(File jarFile, String path) - throws URISyntaxException { - URI uri = new URI(path); - if (uri.isAbsolute()) { - return uri; - } else { - return new File(jarFile.getParentFile(), path.replace('/', File.separatorChar)).toURI(); - } + @VisibleForTesting static URL getClassPathEntry(File jarFile, String path) + throws MalformedURLException { + return new URL(jarFile.toURI().toURL(), path); } }