diff --git a/spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc b/spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc index fd724aa9b61..5628608f346 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-executable-jar-format.adoc @@ -200,12 +200,12 @@ the appropriate launcher: properties (System properties, environment variables, manifest entries or `application.properties`). -[cols="2,4"] |=== |Key |Purpose |`loader.path` -|Comma-separated Classpath, e.g. `lib,${HOME}/app/lib`. Earlier entries take precedence, just like a regular `-classpath` on the `javac` command line. +|Comma-separated Classpath, e.g. `lib,${HOME}/app/lib`. Earlier entries take precedence, + just like a regular `-classpath` on the `javac` command line. |`loader.home` |Location of additional properties file, e.g. `file:///opt/app` @@ -227,25 +227,52 @@ properties (System properties, environment variables, manifest entries or |`loader.system` |Boolean flag to indicate that all properties should be added to System properties (defaults to `false`) + |=== -Manifest entry keys are formed by capitalizing initial letters of words and changing the -separator to "`-`" from "`.`" (e.g. `Loader-Path`). The exception is `loader.main` which -is looked up as `Start-Class` in the manifest for compatibility with `JarLauncher`). +When specified as environment variables or manifest entries, the following names should +be used: + +|=== +|Key | Manifest entry | Environment variable + +|`loader.path` +|`Loader-Path` +|`LOADER_PATH` + +|`loader.home` +| +|`LOADER_HOME` + +|`loader.args` +|`Loader-Args` +|`LOADER_ARGS` + +|`loader.main` +|`Start-Class` +|`LOADER_MAIN` + +|`loader.config.location` +| +|`LOADER_CONFIG_LOCATION` + +|`loader.system` +| +|`LOADER_SYSTEM` + +|=== TIP: Build plugins automatically move the `Main-Class` attribute to `Start-Class` when the fat jar is built. If you are using that, specify the name of the class to launch using the `Main-Class` attribute and leave out `Start-Class`. -Environment variables can be capitalized with underscore separators instead of periods. - * `loader.home` is the directory location of an additional properties file (overriding - the default) as long as `loader.config.location` is not specified. + the default) as long as `loader.config.location` is not specified. * `loader.path` can contain directories (scanned recursively for jar and zip files), archive paths, or wildcard patterns (for the default JVM behavior). -* `loader.path` (if empty) defaults to `lib` (meaning a local directory or a nested one if - running from an archive). Because of this `PropertiesLauncher` behaves the same as - `JarLauncher` when no additional configuration is provided. +* `loader.path` (if empty) defaults to `BOOT-INF/lib` (meaning a local directory or a + nested one if running from an archive). Because of this `PropertiesLauncher` behaves the + same as `JarLauncher` when no additional configuration is provided. * Placeholder replacement is done from System and environment variables plus the properties file itself on all values before use. diff --git a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java index ab5a0322c79..7bc2911fa70 100644 --- a/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java +++ b/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/PropertiesLauncher.java @@ -132,7 +132,7 @@ public class PropertiesLauncher extends Launcher { public PropertiesLauncher() { try { this.home = getHomeDirectory(); - initializeProperties(this.home); + initializeProperties(); initializePaths(); this.parent = createArchive(); } @@ -146,7 +146,7 @@ public class PropertiesLauncher extends Launcher { .resolvePlaceholders(System.getProperty(HOME, "${user.dir}"))); } - private void initializeProperties(File home) throws Exception, IOException { + private void initializeProperties() throws Exception, IOException { String config = "classpath:BOOT-INF/classes/" + SystemPropertyUtils.resolvePlaceholders( SystemPropertyUtils.getProperty(CONFIG_NAME, "application")) @@ -273,14 +273,10 @@ public class PropertiesLauncher extends Launcher { } } - private void initializePaths() throws IOException { - String path = SystemPropertyUtils.getProperty(PATH); - if (path == null) { - path = this.properties.getProperty(PATH); - } + private void initializePaths() throws Exception { + String path = getProperty(PATH); if (path != null) { - this.paths = parsePathsProperty( - SystemPropertyUtils.resolvePlaceholders(path)); + this.paths = parsePathsProperty(path); } log("Nested archive paths: " + this.paths); } diff --git a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java index 9f29293a108..e6d91a6d070 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java +++ b/spring-boot-tools/spring-boot-loader/src/test/java/org/springframework/boot/loader/PropertiesLauncherTests.java @@ -17,16 +17,21 @@ package org.springframework.boot.loader; import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; import java.util.Collections; +import java.util.List; +import java.util.jar.Attributes; +import java.util.jar.Manifest; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.rules.TemporaryFolder; import org.mockito.MockitoAnnotations; import org.springframework.boot.loader.archive.Archive; @@ -45,6 +50,9 @@ public class PropertiesLauncherTests { @Rule public InternalOutputCapture output = new InternalOutputCapture(); + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + @Before public void setup() throws IOException { MockitoAnnotations.initMocks(this); @@ -207,6 +215,23 @@ public class PropertiesLauncherTests { .isEqualTo("[foo, bar]"); } + @SuppressWarnings("unchecked") + @Test + public void testLoadPathCustomizedUsingManifest() throws Exception { + System.setProperty("loader.home", + this.temporaryFolder.getRoot().getAbsolutePath()); + Manifest manifest = new Manifest(); + manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0"); + manifest.getMainAttributes().putValue("Loader-Path", "/foo.jar, /bar"); + File manifestFile = new File(this.temporaryFolder.getRoot(), + "META-INF/MANIFEST.MF"); + manifestFile.getParentFile().mkdirs(); + manifest.write(new FileOutputStream(manifestFile)); + PropertiesLauncher launcher = new PropertiesLauncher(); + assertThat((List) ReflectionTestUtils.getField(launcher, "paths")) + .containsExactly("/foo.jar", "/bar/"); + } + private void waitFor(String value) throws Exception { int count = 0; boolean timeout = false; diff --git a/spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/application.properties b/spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/application.properties index 2dda328f5bc..85a390f4d4e 100644 --- a/spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/application.properties +++ b/spring-boot-tools/spring-boot-loader/src/test/resources/BOOT-INF/classes/application.properties @@ -1,2 +1 @@ loader.main: demo.Application -loader.path: etc/,lib,.