Merge branch '2.4.x' into 2.5.x

Closes gh-27056
This commit is contained in:
Phillip Webb
2021-06-23 15:55:08 -07:00
18 changed files with 344 additions and 108 deletions

View File

@@ -30,7 +30,7 @@ import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Function;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
@@ -89,24 +89,33 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
* Write all entries from the specified jar file.
* @param jarFile the source jar file
* @throws IOException if the entries cannot be written
* @deprecated since 2.4.8 for removal in 2.6.0
*/
@Deprecated
public void writeEntries(JarFile jarFile) throws IOException {
writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER, (name) -> false);
writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER, (entry) -> null);
}
final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler,
Predicate<String> libraryPredicate) throws IOException {
Function<JarEntry, Library> libraryLookup) throws IOException {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarArchiveEntry entry = new JarArchiveEntry(entries.nextElement());
setUpEntry(jarFile, entry);
try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream(jarFile.getInputStream(entry))) {
EntryWriter entryWriter = new InputStreamEntryWriter(inputStream);
JarArchiveEntry transformedEntry = entryTransformer.transform(entry);
if (transformedEntry != null) {
boolean updateLayerIndex = !libraryPredicate.test(entry.getName());
writeEntry(transformedEntry, entryWriter, unpackHandler, updateLayerIndex);
}
JarEntry entry = entries.nextElement();
Library library = libraryLookup.apply(entry);
if (library == null || library.isIncluded()) {
writeEntry(jarFile, entryTransformer, unpackHandler, new JarArchiveEntry(entry), library);
}
}
}
private void writeEntry(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler,
JarArchiveEntry entry, Library library) throws IOException {
setUpEntry(jarFile, entry);
try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream(jarFile.getInputStream(entry))) {
EntryWriter entryWriter = new InputStreamEntryWriter(inputStream);
JarArchiveEntry transformedEntry = entryTransformer.transform(entry);
if (transformedEntry != null) {
writeEntry(transformedEntry, library, entryWriter, unpackHandler);
}
}
}
@@ -160,15 +169,7 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
entry.setTime(getNestedLibraryTime(library));
new CrcAndSize(library::openStream).setupStoredEntry(entry);
try (InputStream inputStream = library.openStream()) {
writeEntry(entry, new InputStreamEntryWriter(inputStream), new LibraryUnpackHandler(library), false);
updateLayerIndex(entry.getName(), library);
}
}
private void updateLayerIndex(String name, Library library) {
if (this.layers != null) {
Layer layer = this.layers.getLayer(library);
this.layersIndex.add(layer, name);
writeEntry(entry, library, new InputStreamEntryWriter(inputStream), new LibraryUnpackHandler(library));
}
}
@@ -249,20 +250,20 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
}
private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws IOException {
writeEntry(entry, entryWriter, UnpackHandler.NEVER, true);
writeEntry(entry, null, entryWriter, UnpackHandler.NEVER);
}
/**
* Perform the actual write of a {@link JarEntry}. All other write methods delegate to
* this one.
* @param entry the entry to write
* @param library the library for the entry or {@code null}
* @param entryWriter the entry writer or {@code null} if there is no content
* @param unpackHandler handles possible unpacking for the entry
* @param updateLayerIndex if the layer index should be updated
* @throws IOException in case of I/O errors
*/
private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter, UnpackHandler unpackHandler,
boolean updateLayerIndex) throws IOException {
private void writeEntry(JarArchiveEntry entry, Library library, EntryWriter entryWriter,
UnpackHandler unpackHandler) throws IOException {
String name = entry.getName();
writeParentDirectoryEntries(name);
if (this.writtenEntries.add(name)) {
@@ -273,16 +274,14 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
entry.setSize(entryWriter.size());
}
entryWriter = addUnpackCommentIfNecessary(entry, entryWriter, unpackHandler);
if (updateLayerIndex) {
updateLayerIndex(entry);
}
updateLayerIndex(entry, library);
writeToArchive(entry, entryWriter);
}
}
private void updateLayerIndex(JarArchiveEntry entry) {
private void updateLayerIndex(JarArchiveEntry entry, Library library) {
if (this.layers != null && !entry.getName().endsWith("/")) {
Layer layer = this.layers.getLayer(entry.getName());
Layer layer = (library != null) ? this.layers.getLayer(library) : this.layers.getLayer(entry.getName());
this.layersIndex.add(layer, entry.getName());
}
}
@@ -294,7 +293,7 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
while (parent.lastIndexOf('/') != -1) {
parent = parent.substring(0, parent.lastIndexOf('/'));
if (!parent.isEmpty()) {
writeEntry(new JarArchiveEntry(parent + "/"), null, UnpackHandler.NEVER, false);
writeEntry(new JarArchiveEntry(parent + "/"), null, null, UnpackHandler.NEVER);
}
}
}

View File

@@ -42,7 +42,7 @@ public class JarModeLibrary extends Library {
}
public JarModeLibrary(LibraryCoordinates coordinates) {
super(getJarName(coordinates), null, LibraryScope.RUNTIME, coordinates, false);
super(getJarName(coordinates), null, LibraryScope.RUNTIME, coordinates, false, false, true);
}
private static LibraryCoordinates createCoordinates(String artifactId) {

View File

@@ -43,11 +43,16 @@ public class Library {
private final boolean local;
private final boolean included;
/**
* Create a new {@link Library}.
* @param file the source file
* @param scope the scope of the library
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
*/
@Deprecated
public Library(File file, LibraryScope scope) {
this(file, scope, false);
}
@@ -57,7 +62,10 @@ public class Library {
* @param file the source file
* @param scope the scope of the library
* @param unpackRequired if the library needs to be unpacked before it can be used
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
*/
@Deprecated
public Library(File file, LibraryScope scope, boolean unpackRequired) {
this(null, file, scope, unpackRequired);
}
@@ -69,7 +77,10 @@ public class Library {
* @param file the source file
* @param scope the scope of the library
* @param unpackRequired if the library needs to be unpacked before it can be used
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
*/
@Deprecated
public Library(String name, File file, LibraryScope scope, boolean unpackRequired) {
this(name, file, scope, null, unpackRequired);
}
@@ -82,7 +93,10 @@ public class Library {
* @param scope the scope of the library
* @param coordinates the library coordinates or {@code null}
* @param unpackRequired if the library needs to be unpacked before it can be used
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
*/
@Deprecated
public Library(String name, File file, LibraryScope scope, LibraryCoordinates coordinates, boolean unpackRequired) {
this(name, file, scope, coordinates, unpackRequired, false);
}
@@ -98,15 +112,37 @@ public class Library {
* @param local if the library is local (part of the same build) to the application
* that is being packaged
* @since 2.4.0
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
*/
@Deprecated
public Library(String name, File file, LibraryScope scope, LibraryCoordinates coordinates, boolean unpackRequired,
boolean local) {
this(name, file, scope, coordinates, unpackRequired, local, true);
}
/**
* Create a new {@link Library}.
* @param name the name of the library as it should be written or {@code null} to use
* the file name
* @param file the source file
* @param scope the scope of the library
* @param coordinates the library coordinates or {@code null}
* @param unpackRequired if the library needs to be unpacked before it can be used
* @param local if the library is local (part of the same build) to the application
* that is being packaged
* @param included if the library is included in the fat jar
* @since 2.4.8
*/
public Library(String name, File file, LibraryScope scope, LibraryCoordinates coordinates, boolean unpackRequired,
boolean local, boolean included) {
this.name = (name != null) ? name : file.getName();
this.file = file;
this.scope = scope;
this.coordinates = coordinates;
this.unpackRequired = unpackRequired;
this.local = local;
this.included = included;
}
/**
@@ -172,4 +208,12 @@ public class Library {
return this.local;
}
/**
* Return if the library is included in the fat jar.
* @return if the library is included
*/
public boolean isIncluded() {
return this.included;
}
}

View File

@@ -25,7 +25,9 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.stream.Collectors;
@@ -191,14 +193,18 @@ public abstract class Packager {
protected final void write(JarFile sourceJar, Libraries libraries, AbstractJarWriter writer) throws IOException {
Assert.notNull(libraries, "Libraries must not be null");
WritableLibraries writeableLibraries = new WritableLibraries(libraries);
write(sourceJar, writer, new PackagedLibraries(libraries));
}
private void write(JarFile sourceJar, AbstractJarWriter writer, PackagedLibraries libraries) throws IOException {
if (isLayered()) {
writer.useLayers(this.layers, this.layersIndex);
}
writer.writeManifest(buildManifest(sourceJar));
writeLoaderClasses(writer);
writer.writeEntries(sourceJar, getEntityTransformer(), writeableLibraries, writeableLibraries::containsEntry);
writeableLibraries.write(writer);
writer.writeEntries(sourceJar, getEntityTransformer(), libraries.getUnpackHandler(),
libraries.getLibraryLookup());
libraries.write(writer);
if (isLayered()) {
writeLayerIndex(writer);
}
@@ -451,11 +457,15 @@ public abstract class Packager {
* An {@link UnpackHandler} that determines that an entry needs to be unpacked if a
* library that requires unpacking has a matching entry name.
*/
private final class WritableLibraries implements UnpackHandler {
private final class PackagedLibraries {
private final Map<String, Library> libraries = new LinkedHashMap<>();
WritableLibraries(Libraries libraries) throws IOException {
private final UnpackHandler unpackHandler;
private final Function<JarEntry, Library> libraryLookup;
PackagedLibraries(Libraries libraries) throws IOException {
libraries.doWithLibraries((library) -> {
if (isZip(library::openStream)) {
addLibrary(library);
@@ -464,6 +474,8 @@ public abstract class Packager {
if (isLayered() && Packager.this.includeRelevantJarModeJars) {
addLibrary(JarModeLibrary.LAYER_TOOLS);
}
this.unpackHandler = new PackagedLibrariesUnpackHandler();
this.libraryLookup = this::lookup;
}
private void addLibrary(Library library) {
@@ -475,41 +487,57 @@ public abstract class Packager {
}
}
@Override
public boolean requiresUnpack(String name) {
Library library = this.libraries.get(name);
return library != null && library.isUnpackRequired();
private Library lookup(JarEntry entry) {
return this.libraries.get(entry.getName());
}
@Override
public String sha1Hash(String name) throws IOException {
Library library = this.libraries.get(name);
Assert.notNull(library, () -> "No library found for entry name '" + name + "'");
return Digest.sha1(library::openStream);
UnpackHandler getUnpackHandler() {
return this.unpackHandler;
}
boolean containsEntry(String name) {
return this.libraries.containsKey(name);
Function<JarEntry, Library> getLibraryLookup() {
return this.libraryLookup;
}
private void write(AbstractJarWriter writer) throws IOException {
void write(AbstractJarWriter writer) throws IOException {
List<String> writtenPaths = new ArrayList<>();
for (Entry<String, Library> entry : this.libraries.entrySet()) {
String path = entry.getKey();
Library library = entry.getValue();
String location = path.substring(0, path.lastIndexOf('/') + 1);
writer.writeNestedLibrary(location, library);
if (library.isIncluded()) {
String location = path.substring(0, path.lastIndexOf('/') + 1);
writer.writeNestedLibrary(location, library);
writtenPaths.add(path);
}
}
if (Packager.this.layout instanceof RepackagingLayout) {
writeClasspathIndex(getLayout(), writer);
if (getLayout() instanceof RepackagingLayout) {
writeClasspathIndex(writtenPaths, (RepackagingLayout) getLayout(), writer);
}
}
private void writeClasspathIndex(Layout layout, AbstractJarWriter writer) throws IOException {
List<String> names = this.libraries.keySet().stream().map((path) -> "- \"" + path + "\"")
.collect(Collectors.toList());
private void writeClasspathIndex(List<String> paths, RepackagingLayout layout, AbstractJarWriter writer)
throws IOException {
List<String> names = paths.stream().map((path) -> "- \"" + path + "\"").collect(Collectors.toList());
writer.writeIndexFile(layout.getClasspathIndexFileLocation(), names);
}
private class PackagedLibrariesUnpackHandler implements UnpackHandler {
@Override
public boolean requiresUnpack(String name) {
Library library = PackagedLibraries.this.libraries.get(name);
return library != null && library.isUnpackRequired();
}
@Override
public String sha1Hash(String name) throws IOException {
Library library = PackagedLibraries.this.libraries.get(name);
Assert.notNull(library, () -> "No library found for entry name '" + name + "'");
return Digest.sha1(library::openStream);
}
}
}
}

View File

@@ -197,9 +197,9 @@ abstract class AbstractPackagerTests<P extends Packager> {
libJarFile.setLastModified(JAN_1_1980);
P packager = createPackager();
execute(packager, (callback) -> {
callback.library(new Library(libJarFile, LibraryScope.COMPILE));
callback.library(new Library(libJarFileToUnpack, LibraryScope.COMPILE, true));
callback.library(new Library(libNonJarFile, LibraryScope.COMPILE));
callback.library(newLibrary(libJarFile, LibraryScope.COMPILE, false));
callback.library(newLibrary(libJarFileToUnpack, LibraryScope.COMPILE, true));
callback.library(newLibrary(libNonJarFile, LibraryScope.COMPILE, false));
});
assertThat(hasPackagedEntry("BOOT-INF/lib/" + libJarFile.getName())).isTrue();
assertThat(hasPackagedEntry("BOOT-INF/lib/" + libJarFileToUnpack.getName())).isTrue();
@@ -226,9 +226,9 @@ abstract class AbstractPackagerTests<P extends Packager> {
File file = this.testJarFile.getFile();
P packager = createPackager(file);
execute(packager, (callback) -> {
callback.library(new Library(libJarFile1, LibraryScope.COMPILE));
callback.library(new Library(libJarFile2, LibraryScope.COMPILE));
callback.library(new Library(libJarFile3, LibraryScope.COMPILE));
callback.library(newLibrary(libJarFile1, LibraryScope.COMPILE, false));
callback.library(newLibrary(libJarFile2, LibraryScope.COMPILE, false));
callback.library(newLibrary(libJarFile3, LibraryScope.COMPILE, false));
});
assertThat(hasPackagedEntry("BOOT-INF/classpath.idx")).isTrue();
String index = getPackagedEntryContent("BOOT-INF/classpath.idx");
@@ -258,9 +258,9 @@ abstract class AbstractPackagerTests<P extends Packager> {
packager.setLayers(layers);
packager.setIncludeRelevantJarModeJars(false);
execute(packager, (callback) -> {
callback.library(new Library(libJarFile1, LibraryScope.COMPILE));
callback.library(new Library(libJarFile2, LibraryScope.COMPILE));
callback.library(new Library(libJarFile3, LibraryScope.COMPILE));
callback.library(newLibrary(libJarFile1, LibraryScope.COMPILE, false));
callback.library(newLibrary(libJarFile2, LibraryScope.COMPILE, false));
callback.library(newLibrary(libJarFile3, LibraryScope.COMPILE, false));
});
assertThat(hasPackagedEntry("BOOT-INF/classpath.idx")).isTrue();
String classpathIndex = getPackagedEntryContent("BOOT-INF/classpath.idx");
@@ -316,8 +316,8 @@ abstract class AbstractPackagerTests<P extends Packager> {
this.testJarFile.addClass("a/b/C.class", ClassWithMainMethod.class);
P packager = createPackager();
assertThatIllegalStateException().isThrownBy(() -> execute(packager, (callback) -> {
callback.library(new Library(libJarFile, LibraryScope.COMPILE, false));
callback.library(new Library(libJarFile, LibraryScope.COMPILE, false));
callback.library(newLibrary(libJarFile, LibraryScope.COMPILE, false));
callback.library(newLibrary(libJarFile, LibraryScope.COMPILE, false));
})).withMessageContaining("Duplicate library");
}
@@ -334,7 +334,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
given(layout.getLibraryLocation(anyString(), eq(scope))).willReturn("test/");
given(layout.getLibraryLocation(anyString(), eq(LibraryScope.COMPILE))).willReturn("test-lib/");
packager.setLayout(layout);
execute(packager, (callback) -> callback.library(new Library(libJarFile, scope)));
execute(packager, (callback) -> callback.library(newLibrary(libJarFile, scope, false)));
assertThat(hasPackagedEntry("test/" + libJarFile.getName())).isTrue();
assertThat(getPackagedManifest().getMainAttributes().getValue("Spring-Boot-Lib")).isEqualTo("test-lib/");
assertThat(getPackagedManifest().getMainAttributes().getValue("Main-Class")).isEqualTo("testLauncher");
@@ -351,7 +351,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
LibraryScope scope = mock(LibraryScope.class);
given(layout.getLauncherClassName()).willReturn("testLauncher");
packager.setLayout(layout);
execute(packager, (callback) -> callback.library(new Library(libJarFile, scope)));
execute(packager, (callback) -> callback.library(newLibrary(libJarFile, scope, false)));
assertThat(getPackagedManifest().getMainAttributes().getValue("Spring-Boot-Lib")).isNull();
assertThat(getPackagedManifest().getMainAttributes().getValue("Main-Class")).isEqualTo("testLauncher");
}
@@ -405,7 +405,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
this.testJarFile.addFile("test/nested.jar", nestedFile);
this.testJarFile.addClass("A.class", ClassWithMainMethod.class);
P packager = createPackager();
execute(packager, (callback) -> callback.library(new Library(nestedFile, LibraryScope.COMPILE)));
execute(packager, (callback) -> callback.library(newLibrary(nestedFile, LibraryScope.COMPILE, false)));
assertThat(getPackagedEntry("BOOT-INF/lib/" + nestedFile.getName()).getMethod()).isEqualTo(ZipEntry.STORED);
assertThat(getPackagedEntry("BOOT-INF/classes/test/nested.jar").getMethod()).isEqualTo(ZipEntry.STORED);
}
@@ -419,7 +419,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
this.testJarFile.addFile(name, nested.getFile());
this.testJarFile.addClass("A.class", ClassWithMainMethod.class);
P packager = createPackager();
execute(packager, (callback) -> callback.library(new Library(nestedFile, LibraryScope.COMPILE, true)));
execute(packager, (callback) -> callback.library(newLibrary(nestedFile, LibraryScope.COMPILE, true)));
assertThat(getPackagedEntry(name).getComment()).startsWith("UNPACK:");
}
@@ -437,7 +437,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
File toZip = new File(this.tempDir, "to-zip");
toZip.createNewFile();
ZipUtil.packEntry(toZip, nestedFile);
callback.library(new Library(nestedFile, LibraryScope.COMPILE));
callback.library(newLibrary(nestedFile, LibraryScope.COMPILE, false));
});
assertThat(getPackagedEntry("BOOT-INF/lib/" + nestedFile.getName()).getSize()).isEqualTo(sourceLength);
}
@@ -498,14 +498,14 @@ abstract class AbstractPackagerTests<P extends Packager> {
@Test
void loaderIsWrittenFirstThenApplicationClassesThenLibraries() throws IOException {
this.testJarFile.addClass("com/example/Application.class", ClassWithMainMethod.class);
File libraryOne = createLibrary();
File libraryTwo = createLibrary();
File libraryThree = createLibrary();
File libraryOne = createLibraryJar();
File libraryTwo = createLibraryJar();
File libraryThree = createLibraryJar();
P packager = createPackager();
execute(packager, (callback) -> {
callback.library(new Library(libraryOne, LibraryScope.COMPILE, false));
callback.library(new Library(libraryTwo, LibraryScope.COMPILE, true));
callback.library(new Library(libraryThree, LibraryScope.COMPILE, false));
callback.library(newLibrary(libraryOne, LibraryScope.COMPILE, false));
callback.library(newLibrary(libraryTwo, LibraryScope.COMPILE, true));
callback.library(newLibrary(libraryThree, LibraryScope.COMPILE, false));
});
assertThat(getPackagedEntryNames()).containsSubsequence("org/springframework/boot/loader/",
"BOOT-INF/classes/com/example/Application.class", "BOOT-INF/lib/" + libraryOne.getName(),
@@ -514,12 +514,12 @@ abstract class AbstractPackagerTests<P extends Packager> {
@Test
void existingEntryThatMatchesUnpackLibraryIsMarkedForUnpack() throws IOException {
File library = createLibrary();
File library = createLibraryJar();
this.testJarFile.addClass("WEB-INF/classes/com/example/Application.class", ClassWithMainMethod.class);
this.testJarFile.addFile("WEB-INF/lib/" + library.getName(), library);
P packager = createPackager(this.testJarFile.getFile("war"));
packager.setLayout(new Layouts.War());
execute(packager, (callback) -> callback.library(new Library(library, LibraryScope.COMPILE, true)));
execute(packager, (callback) -> callback.library(newLibrary(library, LibraryScope.COMPILE, true)));
assertThat(getPackagedEntryNames()).containsSubsequence("org/springframework/boot/loader/",
"WEB-INF/classes/com/example/Application.class", "WEB-INF/lib/" + library.getName());
ZipEntry unpackLibrary = getPackagedEntry("WEB-INF/lib/" + library.getName());
@@ -536,7 +536,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
Layout layout = mock(Layout.class);
LibraryScope scope = mock(LibraryScope.class);
packager.setLayout(layout);
execute(packager, (callback) -> callback.library(new Library(libJarFile, scope)));
execute(packager, (callback) -> callback.library(newLibrary(libJarFile, scope, false)));
assertThat(getPackagedEntryNames()).containsExactly("META-INF/", "META-INF/MANIFEST.MF", "a/", "a/b/",
"a/b/C.class");
}
@@ -583,12 +583,39 @@ abstract class AbstractPackagerTests<P extends Packager> {
assertThat(getPackagedEntry("BOOT-INF/classes/META-INF/test.kotlin_module")).isNotNull();
}
private File createLibrary() throws IOException {
@Test
void entryFiltering() throws Exception {
File webLibrary = createLibraryJar();
File libraryOne = createLibraryJar();
File libraryTwo = createLibraryJar();
this.testJarFile.addClass("WEB-INF/classes/com/example/Application.class", ClassWithMainMethod.class);
this.testJarFile.addFile("WEB-INF/lib/" + webLibrary.getName(), webLibrary);
P packager = createPackager(this.testJarFile.getFile("war"));
packager.setLayout(new Layouts.War());
execute(packager, (callback) -> {
callback.library(newLibrary(webLibrary, LibraryScope.COMPILE, false, false));
callback.library(newLibrary(libraryOne, LibraryScope.COMPILE, false, false));
callback.library(newLibrary(libraryTwo, LibraryScope.COMPILE, false, true));
});
Collection<String> packagedEntryNames = getPackagedEntryNames();
packagedEntryNames.removeIf((name) -> !name.endsWith(".jar"));
assertThat(packagedEntryNames).containsExactly("WEB-INF/lib/" + libraryTwo.getName());
}
private File createLibraryJar() throws IOException {
TestJarFile library = new TestJarFile(this.tempDir);
library.addClass("com/example/library/Library.class", ClassWithoutMainMethod.class);
return library.getFile();
}
private Library newLibrary(File file, LibraryScope scope, boolean unpackRequired) {
return new Library(null, file, scope, null, unpackRequired, false, true);
}
private Library newLibrary(File file, LibraryScope scope, boolean unpackRequired, boolean included) {
return new Library(null, file, scope, null, unpackRequired, false, included);
}
protected final P createPackager() throws IOException {
return createPackager(this.testJarFile.getFile());
}