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 f9cf69aae5b..c6061f93a38 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 @@ -104,7 +104,7 @@ final class ChangeableUrls implements Iterable { return Collections.emptyList(); } try { - return getUrlsFromClassPathAttribute(url, jarFile.getManifest()); + return getUrlsFromManifestClassPathAttribute(jarFile); } catch (IOException ex) { throw new IllegalStateException( @@ -126,7 +126,9 @@ final class ChangeableUrls implements Iterable { return null; } - private static List getUrlsFromClassPathAttribute(URL base, Manifest manifest) { + private static List getUrlsFromManifestClassPathAttribute(JarFile jarFile) + throws IOException { + Manifest manifest = jarFile.getManifest(); if (manifest == null) { return Collections.emptyList(); } @@ -137,9 +139,18 @@ final class ChangeableUrls implements Iterable { } String[] entries = StringUtils.delimitedListToStringArray(classPath, " "); List urls = new ArrayList<>(entries.length); + File parent = new File(jarFile.getName()).getParentFile(); for (String entry : entries) { try { - urls.add(new URL(base, entry)); + File referenced = new File(parent, entry); + if (referenced.exists()) { + urls.add(referenced.toURI().toURL()); + } + else { + System.err.println("Ignoring Class-Path entry " + entry + " found in" + + jarFile.getName() + " as " + referenced + + " does not exist"); + } } 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 eb2e846396d..9e5de5abe54 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 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. @@ -74,15 +74,19 @@ public class ChangeableUrlsTests { @Test public void urlsFromJarClassPathAreConsidered() throws Exception { - URL projectCore = makeUrl("project-core"); - URL projectWeb = makeUrl("project-web"); File relative = this.temporaryFolder.newFolder(); + File jarWithClassPath = makeJarFileWithUrlsInManifestClassPath( + "project-core/target/classes/", "project-web/target/classes/", + "does-not-exist/target/classes", relative.getName() + "/"); + new File(jarWithClassPath.getParentFile(), "project-core/target/classes") + .mkdirs(); + new File(jarWithClassPath.getParentFile(), "project-web/target/classes").mkdirs(); ChangeableUrls urls = ChangeableUrls .fromUrlClassLoader(new URLClassLoader(new URL[] { - makeJarFileWithUrlsInManifestClassPath(projectCore, projectWeb, - relative.getName() + "/"), - makeJarFileWithNoManifest() })); - assertThat(urls.toList()).containsExactly(projectCore, projectWeb, + jarWithClassPath.toURI().toURL(), makeJarFileWithNoManifest() })); + assertThat(urls.toList()).containsExactly( + new URL(jarWithClassPath.toURI().toURL(), "project-core/target/classes/"), + new URL(jarWithClassPath.toURI().toURL(), "project-web/target/classes/"), relative.toURI().toURL()); } @@ -95,7 +99,7 @@ public class ChangeableUrlsTests { return file.toURI().toURL(); } - private URL makeJarFileWithUrlsInManifestClassPath(Object... urls) throws Exception { + private File makeJarFileWithUrlsInManifestClassPath(Object... urls) throws Exception { File classpathJar = this.temporaryFolder.newFile("classpath.jar"); Manifest manifest = new Manifest(); manifest.getMainAttributes().putValue(Attributes.Name.MANIFEST_VERSION.toString(), @@ -103,7 +107,7 @@ public class ChangeableUrlsTests { manifest.getMainAttributes().putValue(Attributes.Name.CLASS_PATH.toString(), StringUtils.arrayToDelimitedString(urls, " ")); new JarOutputStream(new FileOutputStream(classpathJar), manifest).close(); - return classpathJar.toURI().toURL(); + return classpathJar; } private URL makeJarFileWithNoManifest() throws Exception {