From 1412eaa0e0eebf767047564fc476d27fcec2d05e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 12 Apr 2016 13:47:58 +0100 Subject: [PATCH] Handle relative URLs in jar's Class-Path when getting changeable URLs 5e0ba6ea added support for reading a jar manifest's Class-Path attribute when resolving changeable URLs from a URLClassLoader, however it did not handle relative URLs, i.e. URLs without a protocol, correctly. This commit updates ChangeableUrls so that it uses the URL of the JAR that contains the manifest as the base for any new URLs that are created. When the Class-Path entry is relative, this base will be used. When the Class-Path entry is absolutee, URL's constructor will ignore the supplied base. Closes gh-5665 --- .../boot/devtools/restart/ChangeableUrls.java | 6 +++--- .../boot/devtools/restart/ChangeableUrlsTests.java | 8 +++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java index 9356c4cb4e9..927753770c7 100644 --- a/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java +++ b/spring-boot-devtools/src/main/java/org/springframework/boot/devtools/restart/ChangeableUrls.java @@ -94,7 +94,7 @@ final class ChangeableUrls implements Iterable { JarFile jarFile = getJarFileIfPossible(url); if (jarFile != null) { try { - return getUrlsFromClassPathAttribute(jarFile.getManifest()); + return getUrlsFromClassPathAttribute(url, jarFile.getManifest()); } catch (IOException ex) { throw new IllegalStateException( @@ -118,7 +118,7 @@ final class ChangeableUrls implements Iterable { return null; } - private static List getUrlsFromClassPathAttribute(Manifest manifest) { + private static List getUrlsFromClassPathAttribute(URL base, Manifest manifest) { List urls = new ArrayList(); String classPathAttribute = manifest.getMainAttributes() .getValue(Attributes.Name.CLASS_PATH); @@ -126,7 +126,7 @@ final class ChangeableUrls implements Iterable { for (String entry : StringUtils.delimitedListToStringArray(classPathAttribute, " ")) { try { - urls.add(new URL(entry)); + urls.add(new URL(base, entry)); } catch (MalformedURLException ex) { throw new IllegalStateException( diff --git a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java index 723e5588665..117e2d67cc0 100644 --- a/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java +++ b/spring-boot-devtools/src/test/java/org/springframework/boot/devtools/restart/ChangeableUrlsTests.java @@ -77,10 +77,12 @@ public class ChangeableUrlsTests { public void urlsFromJarClassPathAreConsidered() throws Exception { URL projectCore = makeUrl("project-core"); URL projectWeb = makeUrl("project-web"); + File relative = this.temporaryFolder.newFolder(); ChangeableUrls urls = ChangeableUrls.fromUrlClassLoader(new URLClassLoader( new URL[] { makeJarFileWithUrlsInManifestClassPath(projectCore, - projectWeb) })); - assertThat(urls.toList(), contains(projectCore, projectWeb)); + projectWeb, relative.getName() + "/") })); + assertThat(urls.toList(), + contains(projectCore, projectWeb, relative.toURI().toURL())); } private URL makeUrl(String name) throws IOException { @@ -92,7 +94,7 @@ public class ChangeableUrlsTests { return file.toURI().toURL(); } - private URL makeJarFileWithUrlsInManifestClassPath(URL... urls) throws Exception { + private URL makeJarFileWithUrlsInManifestClassPath(Object... urls) throws Exception { File classpathJar = this.temporaryFolder.newFile("classpath.jar"); Manifest manifest = new Manifest(); manifest.getMainAttributes().putValue(Attributes.Name.MANIFEST_VERSION.toString(),