Access classpath lazily to allow later changes to be picked up

Previously, the classpath of bootJar, bootWar, and bootRun was
configured directly as a FileCollection derived from the main source
set's runtime classpath. This direct configuration meant that
subsequent changes to the main source set's runtime classpath may not
have been picked up.

This commit changes the configuration of the classpath to use a
Callable. This indirection allows subsequent changes to the main
source set's runtime classpath to be picked up as long as they
occur before Gradle calls the callable.

Closes gh-29672
This commit is contained in:
Andy Wilkinson
2022-02-08 15:57:33 +00:00
parent 52f1799c20
commit 43ca2d2cb0
8 changed files with 103 additions and 10 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@@ -462,6 +462,30 @@ abstract class AbstractBootArchiveIntegrationTests {
assertExtractedLayers(layerNames, indexedLayers);
}
@TestTemplate
void classesFromASecondarySourceSetCanBeIncludedInTheArchive() throws IOException {
writeMainClass();
File examplePackage = new File(this.gradleBuild.getProjectDir(), "src/secondary/java/example");
examplePackage.mkdirs();
File main = new File(examplePackage, "Secondary.java");
try (PrintWriter writer = new PrintWriter(new FileWriter(main))) {
writer.println("package example;");
writer.println();
writer.println("public class Secondary {}");
}
catch (IOException ex) {
throw new RuntimeException(ex);
}
BuildResult build = this.gradleBuild.build(this.taskName);
assertThat(build.task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
try (JarFile jarFile = new JarFile(new File(this.gradleBuild.getProjectDir(), "build/libs").listFiles()[0])) {
Stream<String> classesEntryNames = jarFile.stream().filter((entry) -> !entry.isDirectory())
.map(JarEntry::getName).filter((name) -> name.startsWith(this.classesPath));
assertThat(classesEntryNames).containsExactly(this.classesPath + "example/Main.class",
this.classesPath + "example/Secondary.class");
}
}
private void copyMainClassApplication() throws IOException {
copyApplication("main");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2021 the original author or authors.
* Copyright 2012-2022 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.
@@ -138,6 +138,16 @@ class BootRunIntegrationTests {
assertThat(result.getOutput()).contains("standard.jar").doesNotContain("starter.jar");
}
@TestTemplate
void classesFromASecondarySourceSetCanBeOnTheClasspath() throws IOException {
File output = new File(this.gradleBuild.getProjectDir(), "src/secondary/java/com/example/bootrun/main");
output.mkdirs();
FileSystemUtils.copyRecursively(new File("src/test/java/com/example/bootrun/main"), output);
BuildResult result = this.gradleBuild.build("bootRun");
assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
assertThat(result.getOutput()).contains("com.example.bootrun.main.CustomMainClass");
}
private void copyMainClassApplication() throws IOException {
copyApplication("main");
}