mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-08-29 03:06:45 +08:00
Fix PropertiesLauncher classpath detection without 'loader.path' set
Update `PropertiesLauncher` to restore classpath detection logic applied when no `loader.path` property is set. Fixes gh-37992
This commit is contained in:
parent
c7bae80585
commit
4e7c0737d4
@ -38,11 +38,7 @@ public class JarLauncher extends ExecutableArchiveLauncher {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isIncludedOnClassPath(Archive.Entry entry) {
|
protected boolean isIncludedOnClassPath(Archive.Entry entry) {
|
||||||
String name = entry.name();
|
return isLibraryFileOrClassesDirectory(entry);
|
||||||
if (entry.isDirectory()) {
|
|
||||||
return name.equals("BOOT-INF/classes/");
|
|
||||||
}
|
|
||||||
return name.startsWith("BOOT-INF/lib/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -50,6 +46,14 @@ public class JarLauncher extends ExecutableArchiveLauncher {
|
|||||||
return "BOOT-INF/";
|
return "BOOT-INF/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isLibraryFileOrClassesDirectory(Archive.Entry entry) {
|
||||||
|
String name = entry.name();
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
return name.equals("BOOT-INF/classes/");
|
||||||
|
}
|
||||||
|
return name.startsWith("BOOT-INF/lib/");
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
new JarLauncher().launch(args);
|
new JarLauncher().launch(args);
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,11 @@ public class PropertiesLauncher extends Launcher {
|
|||||||
private final Properties properties = new Properties();
|
private final Properties properties = new Properties();
|
||||||
|
|
||||||
public PropertiesLauncher() throws Exception {
|
public PropertiesLauncher() throws Exception {
|
||||||
this.archive = Archive.create(Launcher.class);
|
this(Archive.create(Launcher.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertiesLauncher(Archive archive) throws Exception {
|
||||||
|
this.archive = archive;
|
||||||
this.homeDirectory = getHomeDirectory();
|
this.homeDirectory = getHomeDirectory();
|
||||||
initializeProperties();
|
initializeProperties();
|
||||||
this.paths = getPaths();
|
this.paths = getPaths();
|
||||||
@ -464,6 +468,8 @@ public class PropertiesLauncher extends Launcher {
|
|||||||
path = cleanupPath(handleUrl(path));
|
path = cleanupPath(handleUrl(path));
|
||||||
urls.addAll(getClassPathUrlsForPath(path));
|
urls.addAll(getClassPathUrlsForPath(path));
|
||||||
}
|
}
|
||||||
|
urls.addAll(getClassPathUrlsForRoot());
|
||||||
|
debug.log("Using class path URLs %s", urls);
|
||||||
return urls;
|
return urls;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,6 +537,11 @@ public class PropertiesLauncher extends Launcher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Set<URL> getClassPathUrlsForRoot() throws IOException {
|
||||||
|
debug.log("Adding classpath entries from root archive %s", this.archive);
|
||||||
|
return this.archive.getClassPathUrls(JarLauncher::isLibraryFileOrClassesDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
private Predicate<Entry> includeByPrefix(String prefix) {
|
private Predicate<Entry> includeByPrefix(String prefix) {
|
||||||
return (entry) -> (entry.isDirectory() && entry.name().equals(prefix))
|
return (entry) -> (entry.isDirectory() && entry.name().equals(prefix))
|
||||||
|| (isArchive(entry) && entry.name().startsWith(prefix));
|
|| (isArchive(entry) && entry.name().startsWith(prefix));
|
||||||
|
@ -37,11 +37,7 @@ public class WarLauncher extends ExecutableArchiveLauncher {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isIncludedOnClassPath(Archive.Entry entry) {
|
public boolean isIncludedOnClassPath(Archive.Entry entry) {
|
||||||
String name = entry.name();
|
return isLibraryFileOrClassesDirectory(entry);
|
||||||
if (entry.isDirectory()) {
|
|
||||||
return name.equals("WEB-INF/classes/");
|
|
||||||
}
|
|
||||||
return name.startsWith("WEB-INF/lib/") || name.startsWith("WEB-INF/lib-provided/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -49,6 +45,14 @@ public class WarLauncher extends ExecutableArchiveLauncher {
|
|||||||
return "WEB-INF/";
|
return "WEB-INF/";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isLibraryFileOrClassesDirectory(Archive.Entry entry) {
|
||||||
|
String name = entry.name();
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
return name.equals("WEB-INF/classes/");
|
||||||
|
}
|
||||||
|
return name.startsWith("WEB-INF/lib/") || name.startsWith("WEB-INF/lib-provided/");
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
new WarLauncher().launch(args);
|
new WarLauncher().launch(args);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package org.springframework.boot.loader.launch;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
@ -26,7 +27,10 @@ import java.util.LinkedHashSet;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.jar.Attributes;
|
import java.util.jar.Attributes;
|
||||||
|
import java.util.jar.JarFile;
|
||||||
|
import java.util.jar.JarOutputStream;
|
||||||
import java.util.jar.Manifest;
|
import java.util.jar.Manifest;
|
||||||
|
import java.util.zip.ZipEntry;
|
||||||
|
|
||||||
import org.assertj.core.api.Condition;
|
import org.assertj.core.api.Condition;
|
||||||
import org.awaitility.Awaitility;
|
import org.awaitility.Awaitility;
|
||||||
@ -309,8 +313,8 @@ class PropertiesLauncherTests {
|
|||||||
assertThat(Arrays.asList(this.launcher.getArgs("bar"))).hasToString("[foo, bar]");
|
assertThat(Arrays.asList(this.launcher.getArgs("bar"))).hasToString("[foo, bar]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Test
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
void testLoadPathCustomizedUsingManifest() throws Exception {
|
void testLoadPathCustomizedUsingManifest() throws Exception {
|
||||||
System.setProperty("loader.home", this.tempDir.getAbsolutePath());
|
System.setProperty("loader.home", this.tempDir.getAbsolutePath());
|
||||||
Manifest manifest = new Manifest();
|
Manifest manifest = new Manifest();
|
||||||
@ -364,6 +368,29 @@ class PropertiesLauncherTests {
|
|||||||
assertThat(bytes).isNotEmpty();
|
assertThat(bytes).isNotEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // gh-37992
|
||||||
|
void classPathWithoutLoaderPathDefaultsToJarLauncherIncludes() throws Exception {
|
||||||
|
File file = new File(this.tempDir, "test.jar");
|
||||||
|
try (JarOutputStream out = new JarOutputStream(new FileOutputStream(file))) {
|
||||||
|
try (JarFile in = new JarFile(new File("src/test/resources/jars/app.jar"))) {
|
||||||
|
out.putNextEntry(new ZipEntry("BOOT-INF/"));
|
||||||
|
out.putNextEntry(new ZipEntry("BOOT-INF/classes/"));
|
||||||
|
out.putNextEntry(new ZipEntry("BOOT-INF/classes/demo/"));
|
||||||
|
out.putNextEntry(new ZipEntry("BOOT-INF/classes/demo/Application.class"));
|
||||||
|
try (InputStream classIn = in.getInputStream(in.getEntry("demo/Application.class"))) {
|
||||||
|
classIn.transferTo(out);
|
||||||
|
}
|
||||||
|
out.closeEntry();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Archive archive = new JarFileArchive(file);
|
||||||
|
System.setProperty("loader.main", "demo.Application");
|
||||||
|
this.launcher = new PropertiesLauncher(archive);
|
||||||
|
this.launcher.launch(new String[0]);
|
||||||
|
waitFor("Hello World");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private void waitFor(String value) {
|
private void waitFor(String value) {
|
||||||
Awaitility.waitAtMost(Duration.ofSeconds(5)).until(this.output::toString, containsString(value));
|
Awaitility.waitAtMost(Duration.ofSeconds(5)).until(this.output::toString, containsString(value));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user