Add classpath index support for exploded war archives

Update the Maven and Gradle packaging for war files so that a
`classpath.idx` file is written into the archive that provides the
original order of the classpath, as was previously done for jar files.
The `WarLauncher` class will use this file when running as an exploded
archive to ensure that the classpath order is the same as when running
from the far war.

Fixes gh-19875
This commit is contained in:
Scott Frederick
2021-12-09 16:25:30 -06:00
parent 8b5600fca8
commit 8f57f0babb
14 changed files with 168 additions and 76 deletions

View File

@@ -500,9 +500,7 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
expected.add("- \"application\":");
Set<String> applicationContents = new TreeSet<>();
applicationContents.add(" - \"" + this.classesPath + "\"");
if (archiveHasClasspathIndex()) {
applicationContents.add(" - \"" + this.indexPath + "classpath.idx\"");
}
applicationContents.add(" - \"" + this.indexPath + "classpath.idx\"");
applicationContents.add(" - \"" + this.indexPath + "layers.idx\"");
applicationContents.add(" - \"META-INF/\"");
expected.addAll(applicationContents);
@@ -551,9 +549,7 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
Set<String> applicationContents = new TreeSet<>();
applicationContents.add(" - \"" + this.classesPath + "application.properties\"");
applicationContents.add(" - \"" + this.classesPath + "com/\"");
if (archiveHasClasspathIndex()) {
applicationContents.add(" - \"" + this.indexPath + "classpath.idx\"");
}
applicationContents.add(" - \"" + this.indexPath + "classpath.idx\"");
applicationContents.add(" - \"" + this.indexPath + "layers.idx\"");
applicationContents.add(" - \"META-INF/\"");
applicationContents.add(" - \"org/\"");
@@ -634,12 +630,14 @@ abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
return getTask().getArchiveFile().get().getAsFile();
}
abstract void applyLayered(Action<LayeredSpec> action);
boolean archiveHasClasspathIndex() {
return true;
File createPopulatedJar() throws IOException {
addContent();
executeTask();
return getTask().getArchiveFile().get().getAsFile();
}
abstract void applyLayered(Action<LayeredSpec> action);
@SuppressWarnings("unchecked")
void addContent() throws IOException {
this.task.getMainClass().set("com.example.Main");

View File

@@ -103,12 +103,6 @@ class BootJarTests extends AbstractBootArchiveTests<BootJar> {
}
}
private File createPopulatedJar() throws IOException {
addContent();
executeTask();
return getTask().getArchiveFile().get().getAsFile();
}
@Override
void applyLayered(Action<LayeredSpec> action) {
getTask().layered(action);

View File

@@ -26,6 +26,7 @@ import org.springframework.boot.gradle.junit.GradleCompatibility;
* Integration tests for {@link BootWar}.
*
* @author Andy Wilkinson
* @author Scott Frederick
*/
@GradleCompatibility(configurationCache = true)
class BootWarIntegrationTests extends AbstractBootArchiveIntegrationTests {
@@ -37,7 +38,7 @@ class BootWarIntegrationTests extends AbstractBootArchiveIntegrationTests {
@Override
String[] getExpectedApplicationLayerContents(String... additionalFiles) {
Set<String> contents = new TreeSet<>(Arrays.asList(additionalFiles));
contents.addAll(Arrays.asList("WEB-INF/layers.idx", "META-INF/"));
contents.addAll(Arrays.asList("WEB-INF/classpath.idx", "WEB-INF/layers.idx", "META-INF/"));
return contents.toArray(new String[0]);
}

View File

@@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link BootWar}.
*
* @author Andy Wilkinson
* @author Scott Frederick
*/
class BootWarTests extends AbstractBootArchiveTests<BootWar> {
@@ -109,6 +110,28 @@ class BootWarTests extends AbstractBootArchiveTests<BootWar> {
.containsSubsequence("WEB-INF/lib/library.jar", "WEB-INF/lib-provided/provided-library.jar");
}
@Test
void whenWarIsLayeredClasspathIndexPointsToLayeredLibs() throws IOException {
try (JarFile jarFile = new JarFile(createLayeredJar())) {
assertThat(entryLines(jarFile, "WEB-INF/classpath.idx")).containsExactly(
"- \"WEB-INF/lib/first-library.jar\"", "- \"WEB-INF/lib/second-library.jar\"",
"- \"WEB-INF/lib/third-library-SNAPSHOT.jar\"", "- \"WEB-INF/lib/first-project-library.jar\"",
"- \"WEB-INF/lib/second-project-library-SNAPSHOT.jar\"");
}
}
@Test
void classpathIndexPointsToWebInfLibs() throws IOException {
try (JarFile jarFile = new JarFile(createPopulatedJar())) {
assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Classpath-Index"))
.isEqualTo("WEB-INF/classpath.idx");
assertThat(entryLines(jarFile, "WEB-INF/classpath.idx")).containsExactly(
"- \"WEB-INF/lib/first-library.jar\"", "- \"WEB-INF/lib/second-library.jar\"",
"- \"WEB-INF/lib/third-library-SNAPSHOT.jar\"", "- \"WEB-INF/lib/first-project-library.jar\"",
"- \"WEB-INF/lib/second-project-library-SNAPSHOT.jar\"");
}
}
@Override
protected void executeTask() {
getTask().copy();
@@ -124,9 +147,4 @@ class BootWarTests extends AbstractBootArchiveTests<BootWar> {
getTask().layered(action);
}
@Override
boolean archiveHasClasspathIndex() {
return false;
}
}