From 288f5ceaeee90139f82de7f9d81bdd1d441dc22e Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Thu, 23 Jan 2020 11:40:13 +0000 Subject: [PATCH] Fix zip compression of libs in layered jars Closes gh-19792 --- .../boot/gradle/tasks/bundling/BootJar.java | 22 +++++++++++++++---- .../bundling/AbstractBootArchiveTests.java | 13 ++++++++--- .../gradle/tasks/bundling/BootJarTests.java | 13 +++++++++++ 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java index 3088613fe9..e249ff4e75 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java @@ -23,7 +23,10 @@ import java.io.StringWriter; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.concurrent.Callable; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import org.gradle.api.Action; import org.gradle.api.file.CopySpec; @@ -282,18 +285,29 @@ public class BootJar extends Jar implements BootArchive { * Returns the {@link ZipCompression} that should be used when adding the file * represented by the given {@code details} to the jar. *

- * By default, any file in {@code BOOT-INF/lib/} is stored and all other files are - * deflated. + * By default, any file in {@code BOOT-INF/lib/} or + * {@code BOOT-INF/layers//lib} is stored and all other files are deflated. * @param details the details * @return the compression to use */ protected ZipCompression resolveZipCompression(FileCopyDetails details) { - if (details.getRelativePath().getPathString().startsWith("BOOT-INF/lib/")) { - return ZipCompression.STORED; + String path = details.getRelativePath().getPathString(); + for (String prefix : getLibPathPrefixes()) { + if (path.startsWith(prefix)) { + return ZipCompression.STORED; + } } return ZipCompression.DEFLATED; } + private Set getLibPathPrefixes() { + if (this.layers == null) { + return Collections.singleton("BOOT-INF/lib/"); + } + return StreamSupport.stream(this.layers.spliterator(), false) + .map((layer) -> "BOOT-INF/layers/" + layer + "/lib/").collect(Collectors.toSet()); + } + private LaunchScriptConfiguration enableLaunchScriptIfNecessary() { LaunchScriptConfiguration launchScript = this.support.getLaunchScript(); if (launchScript == null) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java index b5f7b0748a..ffffa2f585 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java @@ -110,13 +110,15 @@ abstract class AbstractBootArchiveTests { } @Test - void classpathJarsArePackagedBeneathLibPath() throws IOException { + void classpathJarsArePackagedBeneathLibPathAndAreStored() throws IOException { this.task.setMainClassName("com.example.Main"); this.task.classpath(jarFile("one.jar"), jarFile("two.jar")); executeTask(); try (JarFile jarFile = new JarFile(this.task.getArchiveFile().get().getAsFile())) { - assertThat(jarFile.getEntry(this.libPath + "one.jar")).isNotNull(); - assertThat(jarFile.getEntry(this.libPath + "two.jar")).isNotNull(); + assertThat(jarFile.getEntry(this.libPath + "one.jar")).isNotNull().extracting(ZipEntry::getMethod) + .isEqualTo(ZipEntry.STORED); + assertThat(jarFile.getEntry(this.libPath + "two.jar")).isNotNull().extracting(ZipEntry::getMethod) + .isEqualTo(ZipEntry.STORED); } } @@ -409,6 +411,11 @@ abstract class AbstractBootArchiveTests { this.libPath + "third-library.jar"); } + @Test + void libEntriesAreStored() throws IOException { + + } + protected File jarFile(String name) throws IOException { File file = newFile(name); try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(file))) { diff --git a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java index 8738ad0d2d..4bb8dc037d 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java +++ b/spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java @@ -23,6 +23,7 @@ import java.io.InputStreamReader; import java.util.List; import java.util.jar.JarFile; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; import org.junit.jupiter.api.Test; @@ -100,6 +101,18 @@ class BootJarTests extends AbstractBootArchiveTests { .contains("BOOT-INF/layers/resources/classes/static/test.css"); } + @Test + void whenJarIsLayeredJarsInLibAreStored() throws IOException { + try (JarFile jarFile = new JarFile(createLayeredJar())) { + assertThat(jarFile.getEntry("BOOT-INF/layers/dependencies/lib/first-library.jar").getMethod()) + .isEqualTo(ZipEntry.STORED); + assertThat(jarFile.getEntry("BOOT-INF/layers/dependencies/lib/second-library.jar").getMethod()) + .isEqualTo(ZipEntry.STORED); + assertThat(jarFile.getEntry("BOOT-INF/layers/snapshot-dependencies/lib/third-library-SNAPSHOT.jar") + .getMethod()).isEqualTo(ZipEntry.STORED); + } + } + @Test void whenJarIsLayeredClasspathIndexPointsToLayeredLibs() throws IOException { try (JarFile jarFile = new JarFile(createLayeredJar())) {