Commit 8f116f7e authored by Andy Wilkinson's avatar Andy Wilkinson

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
parent 6328de9e
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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 { ...@@ -50,8 +50,8 @@ public class BootJar extends Jar implements BootArchive {
public BootJar() { public BootJar() {
CopySpec bootInf = getRootSpec().addChildBeforeSpec(getMainSpec()) CopySpec bootInf = getRootSpec().addChildBeforeSpec(getMainSpec())
.into("BOOT-INF"); .into("BOOT-INF");
bootInf.into("lib", classpathFiles(File::isFile));
bootInf.into("classes", classpathFiles(File::isDirectory)); bootInf.into("classes", classpathFiles(File::isDirectory));
bootInf.into("lib", classpathFiles(File::isFile));
} }
private Action<CopySpec> classpathFiles(Spec<File> filter) { private Action<CopySpec> classpathFiles(Spec<File> filter) {
......
/* /*
* 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"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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> { ...@@ -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 { private T configure(T task) throws IOException {
AbstractArchiveTask archiveTask = task; AbstractArchiveTask archiveTask = task;
archiveTask.setBaseName("test"); archiveTask.setBaseName("test");
...@@ -347,4 +368,15 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> { ...@@ -347,4 +368,15 @@ public abstract class AbstractBootArchiveTests<T extends Jar & BootArchive> {
return this.task; 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;
}
} }
...@@ -94,4 +94,14 @@ public class BootWarTests extends AbstractBootArchiveTests<BootWar> { ...@@ -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");
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment