Skip to content

Commit 5ad4d62

Browse files
committed
Fix classpath index so entries match those expected by the launcher
This reverts commit ad16426 and adds some additional tests. Fixes gh-24192
1 parent 826d79b commit 5ad4d62

File tree

13 files changed

+153
-36
lines changed

13 files changed

+153
-36
lines changed

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -243,7 +243,7 @@ private void processFile(FileCopyDetails details) throws IOException {
243243
details.copyTo(this.out);
244244
this.out.closeArchiveEntry();
245245
if (BootZipCopyAction.this.librarySpec.isSatisfiedBy(details)) {
246-
this.writtenLibraries.add(name.substring(name.lastIndexOf('/') + 1));
246+
this.writtenLibraries.add(name);
247247
}
248248
if (BootZipCopyAction.this.layerResolver != null) {
249249
Layer layer = BootZipCopyAction.this.layerResolver.getLayer(details);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2012-2019 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.bootjar.classpath;
18+
19+
import java.net.URL;
20+
import java.net.URLClassLoader;
21+
22+
/**
23+
* Application used for testing classpath handling with BootJar.
24+
*
25+
* @author Andy Wilkinson
26+
*/
27+
public class BootJarClasspathApplication {
28+
29+
protected BootJarClasspathApplication() {
30+
31+
}
32+
33+
public static void main(String[] args) {
34+
int i = 1;
35+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
36+
for (URL url : ((URLClassLoader) classLoader).getURLs()) {
37+
System.out.println(i++ + ". " + url.getFile());
38+
}
39+
}
40+
41+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.example.classpath;
17+
package com.example.bootrun.classpath;
1818

1919
import java.io.File;
2020
import java.lang.management.ManagementFactory;
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.example.jvmargs;
17+
package com.example.bootrun.jvmargs;
1818

1919
import java.lang.management.ManagementFactory;
2020

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.junit.jupiter.api.TestTemplate;
4545

4646
import org.springframework.boot.loader.tools.JarModeLibrary;
47+
import org.springframework.util.FileSystemUtils;
4748
import org.springframework.util.StringUtils;
4849

4950
import static org.assertj.core.api.Assertions.assertThat;
@@ -240,6 +241,28 @@ void multiModuleCustomLayers() throws IOException {
240241
assertExtractedLayers(layerNames, indexedLayers);
241242
}
242243

244+
@TestTemplate
245+
void packagedApplicationClasspath() throws IOException {
246+
copyClasspathApplication();
247+
BuildResult result = this.gradleBuild.build("launch");
248+
String output = result.getOutput();
249+
assertThat(output).containsPattern("1\\. .*classes");
250+
assertThat(output).containsPattern("2\\. .*library-1.0-SNAPSHOT.jar");
251+
assertThat(output).containsPattern("3\\. .*commons-lang3-3.9.jar");
252+
assertThat(output).doesNotContain("4. ");
253+
}
254+
255+
@TestTemplate
256+
void explodedApplicationClasspath() throws IOException {
257+
copyClasspathApplication();
258+
BuildResult result = this.gradleBuild.build("launch");
259+
String output = result.getOutput();
260+
assertThat(output).containsPattern("1\\. .*classes");
261+
assertThat(output).containsPattern("2\\. .*library-1.0-SNAPSHOT.jar");
262+
assertThat(output).containsPattern("3\\. .*commons-lang3-3.9.jar");
263+
assertThat(output).doesNotContain("4. ");
264+
}
265+
243266
private void assertExtractedLayers(List<String> layerNames, Map<String, List<String>> indexedLayers)
244267
throws IOException {
245268
Map<String, List<String>> extractedLayers = readExtractedLayers(this.gradleBuild.getProjectDir(), layerNames);
@@ -339,4 +362,14 @@ private Map<String, List<String>> readExtractedLayers(File root, List<String> la
339362
return extractedLayers;
340363
}
341364

365+
private void copyClasspathApplication() throws IOException {
366+
copyApplication("classpath");
367+
}
368+
369+
private void copyApplication(String name) throws IOException {
370+
File output = new File(this.gradleBuild.getProjectDir(), "src/main/java/com/example/bootjar/" + name);
371+
output.mkdirs();
372+
FileSystemUtils.copyRecursively(new File("src/test/java/com/example/bootjar/" + name), output);
373+
}
374+
342375
}

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -200,9 +200,10 @@ void jarsInLibAreStored() throws IOException {
200200
@Test
201201
void whenJarIsLayeredClasspathIndexPointsToLayeredLibs() throws IOException {
202202
try (JarFile jarFile = new JarFile(createLayeredJar())) {
203-
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("- \"first-library.jar\"",
204-
"- \"second-library.jar\"", "- \"third-library-SNAPSHOT.jar\"", "- \"first-project-library.jar\"",
205-
"- \"second-project-library-SNAPSHOT.jar\"");
203+
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly(
204+
"- \"BOOT-INF/lib/first-library.jar\"", "- \"BOOT-INF/lib/second-library.jar\"",
205+
"- \"BOOT-INF/lib/third-library-SNAPSHOT.jar\"", "- \"BOOT-INF/lib/first-project-library.jar\"",
206+
"- \"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\"");
206207
}
207208
}
208209

@@ -224,9 +225,10 @@ void classpathIndexPointsToBootInfLibs() throws IOException {
224225
try (JarFile jarFile = new JarFile(createPopulatedJar())) {
225226
assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Classpath-Index"))
226227
.isEqualTo("BOOT-INF/classpath.idx");
227-
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("- \"first-library.jar\"",
228-
"- \"second-library.jar\"", "- \"third-library-SNAPSHOT.jar\"", "- \"first-project-library.jar\"",
229-
"- \"second-project-library-SNAPSHOT.jar\"");
228+
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly(
229+
"- \"BOOT-INF/lib/first-library.jar\"", "- \"BOOT-INF/lib/second-library.jar\"",
230+
"- \"BOOT-INF/lib/third-library-SNAPSHOT.jar\"", "- \"BOOT-INF/lib/first-project-library.jar\"",
231+
"- \"BOOT-INF/lib/second-project-library-SNAPSHOT.jar\"");
230232
}
231233
}
232234

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ void applicationPluginMainClassNameIsNotUsedWhenItIsNull() throws IOException {
8181
copyClasspathApplication();
8282
BuildResult result = this.gradleBuild.build("echoMainClassName");
8383
assertThat(result.task(":echoMainClassName").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
84-
assertThat(result.getOutput()).contains("Main class name = com.example.classpath.BootRunClasspathApplication");
84+
assertThat(result.getOutput())
85+
.contains("Main class name = com.example.bootrun.classpath.BootRunClasspathApplication");
8586
}
8687

8788
@TestTemplate
@@ -129,9 +130,9 @@ private void copyJvmArgsApplication() throws IOException {
129130
}
130131

131132
private void copyApplication(String name) throws IOException {
132-
File output = new File(this.gradleBuild.getProjectDir(), "src/main/java/com/example/" + name);
133+
File output = new File(this.gradleBuild.getProjectDir(), "src/main/java/com/example/bootrun/" + name);
133134
output.mkdirs();
134-
FileSystemUtils.copyRecursively(new File("src/test/java/com/example/" + name), output);
135+
FileSystemUtils.copyRecursively(new File("src/test/java/com/example/bootrun/" + name), output);
135136
}
136137

137138
private String canonicalPathOf(String path) throws IOException {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
plugins {
2+
id 'java'
3+
id 'org.springframework.boot' version '{version}'
4+
}
5+
6+
repositories {
7+
mavenCentral()
8+
maven { url "file:repository" }
9+
}
10+
11+
dependencies {
12+
implementation("com.example:library:1.0-SNAPSHOT")
13+
implementation("org.apache.commons:commons-lang3:3.9")
14+
}
15+
16+
task explode(type: Sync) {
17+
dependsOn(bootJar)
18+
destinationDir = file("$buildDir/exploded")
19+
from zipTree(files(bootJar).singleFile)
20+
}
21+
22+
task launch(type: JavaExec) {
23+
classpath = files(explode)
24+
main = 'org.springframework.boot.loader.JarLauncher'
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
plugins {
3+
id 'java'
4+
id 'org.springframework.boot' version '{version}'
5+
}
6+
7+
task launch(type: JavaExec) {
8+
classpath = files(bootJar)
9+
}
10+
11+
repositories {
12+
mavenCentral()
13+
maven { url "file:repository" }
14+
}
15+
16+
dependencies {
17+
implementation("com.example:library:1.0-SNAPSHOT")
18+
implementation("org.apache.commons:commons-lang3:3.9")
19+
}

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -473,15 +473,11 @@ private void write(AbstractJarWriter writer) throws IOException {
473473
}
474474

475475
private void writeClasspathIndex(RepackagingLayout layout, AbstractJarWriter writer) throws IOException {
476-
List<String> names = this.libraries.keySet().stream().map(this::getJarName)
477-
.map((name) -> "- \"" + name + "\"").collect(Collectors.toList());
476+
List<String> names = this.libraries.keySet().stream().map((path) -> "- \"" + path + "\"")
477+
.collect(Collectors.toList());
478478
writer.writeIndexFile(layout.getClasspathIndexFileLocation(), names);
479479
}
480480

481-
private String getJarName(String path) {
482-
return path.substring(path.lastIndexOf('/') + 1);
483-
}
484-
485481
}
486482

487483
}

0 commit comments

Comments
 (0)