From 0c78b2fd3d7b4aeae3c9f53e112cf3a9c6c1ad3c Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 11 Apr 2016 13:47:49 +0100 Subject: [PATCH] Handle fully-qualified Windows paths correctly in the CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, the CLI would always use the class loader to try to locate a source file. This was contrary to the SourceOptions javadoc which states that the class loader is “used to try and load files that are not found in the local filesystem”. This provide to be problematic on Windows when a fully-qualified source file was supplied. The driver letter colon slash (e.g. c:/) at the start of the path is considered invalid for a class path resource by URLClassPath.Loader resulting in an IllegalArgumentException being thrown. A workaround for this URLClassPath behaviour was added in a71c9b5d. It was removed as part of reworking LaunchedURLClassLoader to use a conventional delegation model in 87fe0b2a. It was then reinstated in cc140b2c. This work around is undesirable as it causes LaunchedURLClassLoader’s behaviour to diverge from URLClassLoader’s behaviour (this is contrary to the comments in the test added in a71c9b5d which incorrectly tests the two class loader with different class paths. If the two class loaders are created with the same class path then their behaviour is the same). This commit updates SourceOptions to make its behaviour match its javadoc so that a search of the class path is only performed if the filename doesn’t exist on the filesystem. Furthermore, when running on Windows, if the filename is an absolute path no further searching is performed as the path cannot reliably be used to search the class path due to the behaviour of URLClassPath.Loader when given a path that is an absolute file path on Windows. This ensures that the user is presented with an error message indicating that the file could not be found. Closes gh-5650 --- .../cli/command/options/SourceOptions.java | 26 ++++++++++++++++--- .../boot/loader/LaunchedURLClassLoader.java | 7 +---- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/SourceOptions.java b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/SourceOptions.java index 4165466b90..0b1897a73f 100644 --- a/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/SourceOptions.java +++ b/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/options/SourceOptions.java @@ -16,6 +16,7 @@ package org.springframework.boot.cli.command.options; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -78,13 +79,20 @@ public class SourceOptions { if ("--".equals(filename)) { break; } - List urls = ResourceUtils.getUrls(filename, classLoader); + List urls = new ArrayList(); + File fileCandidate = new File(filename); + if (fileCandidate.isFile()) { + urls.add(fileCandidate.getAbsoluteFile().toURI().toString()); + } + else if (!isAbsoluteWindowsFile(fileCandidate)) { + urls.addAll(ResourceUtils.getUrls(filename, classLoader)); + } for (String url : urls) { - if (url.endsWith(".groovy") || url.endsWith(".java")) { + if (isSource(url)) { sources.add(url); } } - if ((filename.endsWith(".groovy") || filename.endsWith(".java"))) { + if (isSource(filename)) { if (urls.isEmpty()) { throw new IllegalArgumentException("Can't find " + filename); } @@ -100,6 +108,18 @@ public class SourceOptions { this.sources = Collections.unmodifiableList(sources); } + private boolean isAbsoluteWindowsFile(File file) { + return isWindows() && file.isAbsolute(); + } + + private boolean isWindows() { + return File.separatorChar == '\\'; + } + + private boolean isSource(String name) { + return name.endsWith(".java") || name.endsWith(".groovy"); + } + public List getArgs() { return this.args; } diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java index a9d0e1d469..5609899813 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/LaunchedURLClassLoader.java @@ -50,12 +50,7 @@ public class LaunchedURLClassLoader extends URLClassLoader { public URL findResource(String name) { Handler.setUseFastConnectionExceptions(true); try { - try { - return super.findResource(name); - } - catch (IllegalArgumentException ex) { - return null; - } + return super.findResource(name); } finally { Handler.setUseFastConnectionExceptions(false);