From b51c7386aa8e1fdf604ca3b0d017661d196f4102 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 17 Mar 2020 12:41:26 +0000 Subject: [PATCH] Fix detection of application home for paths containing spaces Fixes gh-20531 --- .../boot/system/ApplicationHome.java | 7 +- .../boot/system/ApplicationHomeTests.java | 81 +++++++++++++++++++ 2 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 spring-boot-project/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/system/ApplicationHome.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/system/ApplicationHome.java index 15e508df86..00f0d88e56 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/system/ApplicationHome.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/system/ApplicationHome.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.security.CodeSource; @@ -116,12 +117,12 @@ public class ApplicationHome { return false; } - private File findSource(URL location) throws IOException { + private File findSource(URL location) throws IOException, URISyntaxException { URLConnection connection = location.openConnection(); if (connection instanceof JarURLConnection) { return getRootJarFile(((JarURLConnection) connection).getJarFile()); } - return new File(location.getPath()); + return new File(location.toURI()); } private File getRootJarFile(JarFile jarFile) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java new file mode 100644 index 0000000000..2f24c242c8 --- /dev/null +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/system/ApplicationHomeTests.java @@ -0,0 +1,81 @@ +/* + * Copyright 2012-2020 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.system; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import net.bytebuddy.ByteBuddy; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import org.springframework.util.FileCopyUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ApplicationHome}. + * + * @author Andy Wilkinson + */ +public class ApplicationHomeTests { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Test + public void whenSourceClassIsProvidedThenApplicationHomeReflectsItsLocation() throws Exception { + File app = this.temporaryFolder.newFolder("app"); + ApplicationHome applicationHome = createApplicationHome(app); + assertThat(applicationHome.getDir()).isEqualTo(app); + } + + @Test + public void whenSourceClassIsProvidedWithSpaceInItsPathThenApplicationHomeReflectsItsLocation() throws Exception { + File app = this.temporaryFolder.newFolder("app location"); + ApplicationHome applicationHome = createApplicationHome(app); + assertThat(applicationHome.getDir()).isEqualTo(app); + } + + private ApplicationHome createApplicationHome(File location) throws Exception { + File examplePackage = new File(location, "com/example"); + examplePackage.mkdirs(); + FileCopyUtils.copy( + new ByteArrayInputStream( + new ByteBuddy().subclass(Object.class).name("com.example.Source").make().getBytes()), + new FileOutputStream(new File(examplePackage, "Source.class"))); + try (URLClassLoader classLoader = new URLClassLoader(new URL[] { location.toURI().toURL() })) { + Class sourceClass = classLoader.loadClass("com.example.Source"); + // Separate thread to bypass stack-based unit test detection in + // ApplicationHome + ExecutorService executor = Executors.newSingleThreadExecutor(); + try { + return executor.submit(() -> new ApplicationHome(sourceClass)).get(); + } + finally { + executor.shutdown(); + } + } + } + +}