Allow loader.path to refer to nested jars
Previously, each entry in loader.path could only refer to a standard jar file. Refering to such a jar would add all of the classes in the root of the jar to the class path. This commit adds support for referencing a directory within a jar file that contains one or more nested jars. For example: $ java -jar -Dloader.path='jar:file:./lib.jar/!BOOT-INF/lib' my.jar This will add all of the classes in all of that jars in the BOOT-INF/lib directory of lib.jar to the class path. See gh-8334
This commit is contained in:
committed by
Andy Wilkinson
parent
605b0aefc6
commit
3701cce88f
@@ -0,0 +1 @@
|
||||
loader.path=jar:file:../executable-props/target/executable-props-0.0.1.BUILD-SNAPSHOT-full.jar/!BOOT-INF/lib
|
||||
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.boot.launcher.it</groupId>
|
||||
<artifactId>executable-props-lib</artifactId>
|
||||
<version>0.0.1.BUILD-SNAPSHOT</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.1</version>
|
||||
<configuration>
|
||||
<source>1.6</source>
|
||||
<target>1.6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<version>2.10</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack</id>
|
||||
<phase>prepare-package</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>@project.groupId@</groupId>
|
||||
<artifactId>@project.artifactId@</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<type>jar</type>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
<outputDirectory>${project.build.directory}/assembly</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>2.4</version>
|
||||
<configuration>
|
||||
<descriptors>
|
||||
<descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor>
|
||||
</descriptors>
|
||||
<archive>
|
||||
<manifest>
|
||||
<mainClass>org.springframework.boot.loader.PropertiesLauncher</mainClass>
|
||||
</manifest>
|
||||
<manifestEntries>
|
||||
<Start-Class>org.springframework.boot.load.it.props.EmbeddedJarStarter</Start-Class>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>jar-with-dependencies</id>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>4.1.4.RELEASE</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<assembly
|
||||
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
|
||||
<id>full</id>
|
||||
<formats>
|
||||
<format>jar</format>
|
||||
</formats>
|
||||
<includeBaseDirectory>false</includeBaseDirectory>
|
||||
<dependencySets>
|
||||
<dependencySet>
|
||||
<useProjectArtifact/>
|
||||
<includes>
|
||||
<include>${project.groupId}:${project.artifactId}</include>
|
||||
</includes>
|
||||
<outputDirectory>BOOT-INF/classes</outputDirectory>
|
||||
<unpack>true</unpack>
|
||||
</dependencySet>
|
||||
</dependencySets>
|
||||
<fileSets>
|
||||
<fileSet>
|
||||
<directory>${project.build.directory}/assembly</directory>
|
||||
<outputDirectory>/</outputDirectory>
|
||||
</fileSet>
|
||||
</fileSets>
|
||||
</assembly>
|
||||
@@ -0,0 +1 @@
|
||||
message: World
|
||||
@@ -0,0 +1,17 @@
|
||||
def jarfile = './target/executable-props-lib-0.0.1.BUILD-SNAPSHOT-full.jar'
|
||||
|
||||
new File("${basedir}/application.properties").delete()
|
||||
|
||||
String exec(String command) {
|
||||
def proc = command.execute([], basedir)
|
||||
proc.waitFor()
|
||||
proc.err.text
|
||||
}
|
||||
|
||||
String out = exec("java -jar ${jarfile}")
|
||||
assert out.contains('Hello Embedded World!'),
|
||||
'Using -jar my.jar should use the application.properties from the jar\n' + out
|
||||
|
||||
out = exec("java -cp ${jarfile} org.springframework.boot.loader.PropertiesLauncher")
|
||||
assert out.contains('Hello Embedded World!'),
|
||||
'Using -cp my.jar with PropertiesLauncher should use the application.properties from the jar\n' + out
|
||||
@@ -21,12 +21,10 @@ import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.jar.Manifest;
|
||||
@@ -469,10 +467,10 @@ public class PropertiesLauncher extends Launcher {
|
||||
debug("Adding classpath entries from archive " + archive.getUrl() + root);
|
||||
lib.add(archive);
|
||||
}
|
||||
Archive nested = getNestedArchive(root);
|
||||
if (nested != null) {
|
||||
List<Archive> nestedArchives = getNestedArchives(root);
|
||||
if (nestedArchives != null) {
|
||||
debug("Adding classpath entries from nested " + root);
|
||||
lib.add(nested);
|
||||
lib.addAll(nestedArchives);
|
||||
}
|
||||
return lib;
|
||||
}
|
||||
@@ -490,19 +488,24 @@ public class PropertiesLauncher extends Launcher {
|
||||
return null;
|
||||
}
|
||||
|
||||
private Archive getNestedArchive(String root) throws Exception {
|
||||
private List<Archive> getNestedArchives(String root) throws Exception {
|
||||
if (root.startsWith("/")
|
||||
|| this.parent.getUrl().equals(this.home.toURI().toURL())) {
|
||||
// If home dir is same as parent archive, no need to add it twice.
|
||||
return null;
|
||||
}
|
||||
EntryFilter filter = new PrefixMatchingArchiveFilter(root);
|
||||
if (this.parent.getNestedArchives(filter).isEmpty()) {
|
||||
return null;
|
||||
Archive parent = this.parent;
|
||||
if (root.startsWith("jar:file:") && root.contains("!")) {
|
||||
int index = root.indexOf("!");
|
||||
String file = root.substring("jar:file:".length(), index);
|
||||
parent = new JarFileArchive(new File(file));
|
||||
root = root.substring(index + 1, root.length());
|
||||
while (root.startsWith("/")) {
|
||||
root = root.substring(1);
|
||||
}
|
||||
}
|
||||
// If there are more archives nested in this subdirectory (root) then create a new
|
||||
// virtual archive for them, and have it added to the classpath
|
||||
return new FilteredArchive(this.parent, filter);
|
||||
EntryFilter filter = new PrefixMatchingArchiveFilter(root);
|
||||
return parent.getNestedArchives(filter);
|
||||
}
|
||||
|
||||
private void addNestedEntries(List<Archive> lib) {
|
||||
@@ -626,47 +629,4 @@ public class PropertiesLauncher extends Launcher {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Decorator to apply an {@link Archive.EntryFilter} to an existing {@link Archive}.
|
||||
*/
|
||||
private static class FilteredArchive implements Archive {
|
||||
|
||||
private final Archive parent;
|
||||
|
||||
private final EntryFilter filter;
|
||||
|
||||
FilteredArchive(Archive parent, EntryFilter filter) {
|
||||
this.parent = parent;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URL getUrl() throws MalformedURLException {
|
||||
return this.parent.getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest getManifest() throws IOException {
|
||||
return this.parent.getManifest();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Entry> iterator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Archive> getNestedArchives(final EntryFilter filter)
|
||||
throws IOException {
|
||||
return this.parent.getNestedArchives(new EntryFilter() {
|
||||
@Override
|
||||
public boolean matches(Entry entry) {
|
||||
return FilteredArchive.this.filter.matches(entry)
|
||||
&& filter.matches(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user