Fix classpath index so entries match those expected by the launcher
This reverts commit ad164269e9 and adds
some additional tests.
Fixes gh-24192
This commit is contained in:
parent
826d79be3e
commit
5ad4d627fd
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
|
|
@ -243,7 +243,7 @@ class BootZipCopyAction implements CopyAction {
|
|||
details.copyTo(this.out);
|
||||
this.out.closeArchiveEntry();
|
||||
if (BootZipCopyAction.this.librarySpec.isSatisfiedBy(details)) {
|
||||
this.writtenLibraries.add(name.substring(name.lastIndexOf('/') + 1));
|
||||
this.writtenLibraries.add(name);
|
||||
}
|
||||
if (BootZipCopyAction.this.layerResolver != null) {
|
||||
Layer layer = BootZipCopyAction.this.layerResolver.getLayer(details);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2012-2019 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 com.example.bootjar.classpath;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
/**
|
||||
* Application used for testing classpath handling with BootJar.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class BootJarClasspathApplication {
|
||||
|
||||
protected BootJarClasspathApplication() {
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int i = 1;
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
|
||||
System.out.println(i++ + ". " + url.getFile());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.classpath;
|
||||
package com.example.bootrun.classpath;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.example.jvmargs;
|
||||
package com.example.bootrun.jvmargs;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
|
|
@ -44,6 +44,7 @@ import org.gradle.testkit.runner.UnexpectedBuildFailure;
|
|||
import org.junit.jupiter.api.TestTemplate;
|
||||
|
||||
import org.springframework.boot.loader.tools.JarModeLibrary;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
|
@ -240,6 +241,28 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {
|
|||
assertExtractedLayers(layerNames, indexedLayers);
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void packagedApplicationClasspath() throws IOException {
|
||||
copyClasspathApplication();
|
||||
BuildResult result = this.gradleBuild.build("launch");
|
||||
String output = result.getOutput();
|
||||
assertThat(output).containsPattern("1\\. .*classes");
|
||||
assertThat(output).containsPattern("2\\. .*library-1.0-SNAPSHOT.jar");
|
||||
assertThat(output).containsPattern("3\\. .*commons-lang3-3.9.jar");
|
||||
assertThat(output).doesNotContain("4. ");
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
void explodedApplicationClasspath() throws IOException {
|
||||
copyClasspathApplication();
|
||||
BuildResult result = this.gradleBuild.build("launch");
|
||||
String output = result.getOutput();
|
||||
assertThat(output).containsPattern("1\\. .*classes");
|
||||
assertThat(output).containsPattern("2\\. .*library-1.0-SNAPSHOT.jar");
|
||||
assertThat(output).containsPattern("3\\. .*commons-lang3-3.9.jar");
|
||||
assertThat(output).doesNotContain("4. ");
|
||||
}
|
||||
|
||||
private void assertExtractedLayers(List<String> layerNames, Map<String, List<String>> indexedLayers)
|
||||
throws IOException {
|
||||
Map<String, List<String>> extractedLayers = readExtractedLayers(this.gradleBuild.getProjectDir(), layerNames);
|
||||
|
|
@ -339,4 +362,14 @@ class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests {
|
|||
return extractedLayers;
|
||||
}
|
||||
|
||||
private void copyClasspathApplication() throws IOException {
|
||||
copyApplication("classpath");
|
||||
}
|
||||
|
||||
private void copyApplication(String name) throws IOException {
|
||||
File output = new File(this.gradleBuild.getProjectDir(), "src/main/java/com/example/bootjar/" + name);
|
||||
output.mkdirs();
|
||||
FileSystemUtils.copyRecursively(new File("src/test/java/com/example/bootjar/" + name), output);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
|
|
@ -200,9 +200,10 @@ class BootJarTests extends AbstractBootArchiveTests<TestBootJar> {
|
|||
@Test
|
||||
void whenJarIsLayeredClasspathIndexPointsToLayeredLibs() throws IOException {
|
||||
try (JarFile jarFile = new JarFile(createLayeredJar())) {
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("- \"first-library.jar\"",
|
||||
"- \"second-library.jar\"", "- \"third-library-SNAPSHOT.jar\"", "- \"first-project-library.jar\"",
|
||||
"- \"second-project-library-SNAPSHOT.jar\"");
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly(
|
||||
"- \"BOOT-INF/lib/first-library.jar\"", "- \"BOOT-INF/lib/second-library.jar\"",
|
||||
"- \"BOOT-INF/lib/third-library-SNAPSHOT.jar\"", "- \"BOOT-INF/lib/first-project-library.jar\"",
|
||||
"- \"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,9 +225,10 @@ class BootJarTests extends AbstractBootArchiveTests<TestBootJar> {
|
|||
try (JarFile jarFile = new JarFile(createPopulatedJar())) {
|
||||
assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Classpath-Index"))
|
||||
.isEqualTo("BOOT-INF/classpath.idx");
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("- \"first-library.jar\"",
|
||||
"- \"second-library.jar\"", "- \"third-library-SNAPSHOT.jar\"", "- \"first-project-library.jar\"",
|
||||
"- \"second-project-library-SNAPSHOT.jar\"");
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly(
|
||||
"- \"BOOT-INF/lib/first-library.jar\"", "- \"BOOT-INF/lib/second-library.jar\"",
|
||||
"- \"BOOT-INF/lib/third-library-SNAPSHOT.jar\"", "- \"BOOT-INF/lib/first-project-library.jar\"",
|
||||
"- \"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -81,7 +81,8 @@ class BootRunIntegrationTests {
|
|||
copyClasspathApplication();
|
||||
BuildResult result = this.gradleBuild.build("echoMainClassName");
|
||||
assertThat(result.task(":echoMainClassName").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
assertThat(result.getOutput()).contains("Main class name = com.example.classpath.BootRunClasspathApplication");
|
||||
assertThat(result.getOutput())
|
||||
.contains("Main class name = com.example.bootrun.classpath.BootRunClasspathApplication");
|
||||
}
|
||||
|
||||
@TestTemplate
|
||||
|
|
@ -129,9 +130,9 @@ class BootRunIntegrationTests {
|
|||
}
|
||||
|
||||
private void copyApplication(String name) throws IOException {
|
||||
File output = new File(this.gradleBuild.getProjectDir(), "src/main/java/com/example/" + name);
|
||||
File output = new File(this.gradleBuild.getProjectDir(), "src/main/java/com/example/bootrun/" + name);
|
||||
output.mkdirs();
|
||||
FileSystemUtils.copyRecursively(new File("src/test/java/com/example/" + name), output);
|
||||
FileSystemUtils.copyRecursively(new File("src/test/java/com/example/bootrun/" + name), output);
|
||||
}
|
||||
|
||||
private String canonicalPathOf(String path) throws IOException {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '{version}'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "file:repository" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.example:library:1.0-SNAPSHOT")
|
||||
implementation("org.apache.commons:commons-lang3:3.9")
|
||||
}
|
||||
|
||||
task explode(type: Sync) {
|
||||
dependsOn(bootJar)
|
||||
destinationDir = file("$buildDir/exploded")
|
||||
from zipTree(files(bootJar).singleFile)
|
||||
}
|
||||
|
||||
task launch(type: JavaExec) {
|
||||
classpath = files(explode)
|
||||
main = 'org.springframework.boot.loader.JarLauncher'
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'org.springframework.boot' version '{version}'
|
||||
}
|
||||
|
||||
task launch(type: JavaExec) {
|
||||
classpath = files(bootJar)
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url "file:repository" }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("com.example:library:1.0-SNAPSHOT")
|
||||
implementation("org.apache.commons:commons-lang3:3.9")
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
|
|
@ -473,15 +473,11 @@ public abstract class Packager {
|
|||
}
|
||||
|
||||
private void writeClasspathIndex(RepackagingLayout layout, AbstractJarWriter writer) throws IOException {
|
||||
List<String> names = this.libraries.keySet().stream().map(this::getJarName)
|
||||
.map((name) -> "- \"" + name + "\"").collect(Collectors.toList());
|
||||
List<String> names = this.libraries.keySet().stream().map((path) -> "- \"" + path + "\"")
|
||||
.collect(Collectors.toList());
|
||||
writer.writeIndexFile(layout.getClasspathIndexFileLocation(), names);
|
||||
}
|
||||
|
||||
private String getJarName(String path) {
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
|
|
@ -234,7 +234,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
|
|||
String index = getPackagedEntryContent("BOOT-INF/classpath.idx");
|
||||
String[] libraries = index.split("\\r?\\n");
|
||||
List<String> expected = Stream.of(libJarFile1, libJarFile2, libJarFile3)
|
||||
.map((jar) -> "- \"" + jar.getName() + "\"").collect(Collectors.toList());
|
||||
.map((jar) -> "- \"BOOT-INF/lib/" + jar.getName() + "\"").collect(Collectors.toList());
|
||||
assertThat(Arrays.asList(libraries)).containsExactlyElementsOf(expected);
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +265,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
|
|||
assertThat(hasPackagedEntry("BOOT-INF/classpath.idx")).isTrue();
|
||||
String classpathIndex = getPackagedEntryContent("BOOT-INF/classpath.idx");
|
||||
List<String> expectedClasspathIndex = Stream.of(libJarFile1, libJarFile2, libJarFile3)
|
||||
.map((file) -> "- \"" + file.getName() + "\"").collect(Collectors.toList());
|
||||
.map((file) -> "- \"BOOT-INF/lib/" + file.getName() + "\"").collect(Collectors.toList());
|
||||
assertThat(Arrays.asList(classpathIndex.split("\\n"))).containsExactlyElementsOf(expectedClasspathIndex);
|
||||
assertThat(hasPackagedEntry("BOOT-INF/layers.idx")).isTrue();
|
||||
String layersIndex = getPackagedEntryContent("BOOT-INF/layers.idx");
|
||||
|
|
@ -296,7 +296,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
|
|||
assertThat(hasPackagedEntry("BOOT-INF/classpath.idx")).isTrue();
|
||||
String classpathIndex = getPackagedEntryContent("BOOT-INF/classpath.idx");
|
||||
assertThat(Arrays.asList(classpathIndex.split("\\n")))
|
||||
.containsExactly("- \"spring-boot-jarmode-layertools.jar\"");
|
||||
.containsExactly("- \"BOOT-INF/lib/spring-boot-jarmode-layertools.jar\"");
|
||||
assertThat(hasPackagedEntry("BOOT-INF/layers.idx")).isTrue();
|
||||
String layersIndex = getPackagedEntryContent("BOOT-INF/layers.idx");
|
||||
List<String> expectedLayers = new ArrayList<>();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2021 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.
|
||||
|
|
@ -78,11 +78,11 @@ class ClassPathIndexFileTests {
|
|||
ClassPathIndexFile indexFile = copyAndLoadTestIndexFile();
|
||||
List<URL> urls = indexFile.getUrls();
|
||||
List<File> expected = new ArrayList<>();
|
||||
expected.add(new File(this.temp, "a.jar"));
|
||||
expected.add(new File(this.temp, "b.jar"));
|
||||
expected.add(new File(this.temp, "c.jar"));
|
||||
expected.add(new File(this.temp, "d.jar"));
|
||||
expected.add(new File(this.temp, "e.jar"));
|
||||
expected.add(new File(this.temp, "BOOT-INF/layers/one/lib/a.jar"));
|
||||
expected.add(new File(this.temp, "BOOT-INF/layers/one/lib/b.jar"));
|
||||
expected.add(new File(this.temp, "BOOT-INF/layers/one/lib/c.jar"));
|
||||
expected.add(new File(this.temp, "BOOT-INF/layers/two/lib/d.jar"));
|
||||
expected.add(new File(this.temp, "BOOT-INF/layers/two/lib/e.jar"));
|
||||
assertThat(urls).containsExactly(expected.stream().map(this::toUrl).toArray(URL[]::new));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
- "a.jar"
|
||||
- "b.jar"
|
||||
- "c.jar"
|
||||
- "d.jar"
|
||||
- "e.jar"
|
||||
- "BOOT-INF/layers/one/lib/a.jar"
|
||||
- "BOOT-INF/layers/one/lib/b.jar"
|
||||
- "BOOT-INF/layers/one/lib/c.jar"
|
||||
- "BOOT-INF/layers/two/lib/d.jar"
|
||||
- "BOOT-INF/layers/two/lib/e.jar"
|
||||
|
|
|
|||
Loading…
Reference in New Issue