Align ordering of BootJar and BootWar archive entries

Previously, the ordering of the entries in an archive produced by
BootJar was different to the ordering of the entries in an archive
produced by BootWar. The latter placed application classes before
any nested jars, whereas the former was the other way around.

This commit updates BootJar to use the same ordering as BootWar and
adds tests to verify that the ordering is the following:

1. Loader classes
2. Application classes (BOOT-INF/classes or WEB-INF/classes)
3. Nested jars (BOOT-INF/lib or WEB-INF/lib)
4. Provided nested jars in a war (WEB-INF/lib-provided)

The tests also verify that the position of a library is not affected
by it requiring unpacking.

See gh-11695
See gh-11696
This commit is contained in:
Andy Wilkinson 2018-01-31 14:21:58 +00:00
parent 6328de9e20
commit 8f116f7e6f
3 changed files with 45 additions and 3 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -50,8 +50,8 @@ public class BootJar extends Jar implements BootArchive {
public BootJar() {
CopySpec bootInf = getRootSpec().addChildBeforeSpec(getMainSpec())
.into("BOOT-INF");
bootInf.into("lib", classpathFiles(File::isFile));
bootInf.into("classes", classpathFiles(File::isDirectory));
bootInf.into("lib", classpathFiles(File::isFile));
}
private Action<CopySpec> classpathFiles(Spec<File> filter) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -336,6 +336,27 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
}
}
@Test
public void loaderIsWrittenFirstThenApplicationClassesThenLibraries()
throws IOException {
this.task.setMainClassName("com.example.Main");
File classpathFolder = this.temp.newFolder();
File applicationClass = new File(classpathFolder,
"com/example/Application.class");
applicationClass.getParentFile().mkdirs();
applicationClass.createNewFile();
this.task.classpath(classpathFolder, this.temp.newFile("first-library.jar"),
this.temp.newFile("second-library.jar"),
this.temp.newFile("third-library.jar"));
this.task.requiresUnpack("second-library.jar");
this.task.execute();
assertThat(getEntryNames(this.task.getArchivePath())).containsSubsequence(
"org/springframework/boot/loader/",
this.classesPath + "/com/example/Application.class",
this.libPath + "/first-library.jar", this.libPath + "/second-library.jar",
this.libPath + "/third-library.jar");
}
private T configure(T task) throws IOException {
AbstractArchiveTask archiveTask = task;
archiveTask.setBaseName("test");
@ -347,4 +368,15 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
return this.task;
}
protected List<String> getEntryNames(File file) throws IOException {
List<String> entryNames = new ArrayList<>();
try (JarFile jarFile = new JarFile(file)) {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
entryNames.add(entries.nextElement().getName());
}
}
return entryNames;
}
}

View File

@ -94,4 +94,14 @@ public class BootWarTests extends AbstractBootArchiveTests<BootWar> {
}
}
@Test
public void libProvidedEntriesAreWrittenAfterLibEntries() throws IOException {
getTask().setMainClassName("com.example.Main");
getTask().classpath(this.temp.newFile("library.jar"));
getTask().providedClasspath(this.temp.newFile("provided-library.jar"));
getTask().execute();
assertThat(getEntryNames(getTask().getArchivePath())).containsSubsequence(
"WEB-INF/lib/library.jar", "WEB-INF/lib-provided/provided-library.jar");
}
}