From 5bf8f778e2d9ad921760ee008a24cc3810ced04a Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 27 Mar 2017 15:30:29 +0100 Subject: [PATCH] Don't write the default loader classes when a custom launcher is used --- .../gradle/bundling/BootArchiveSupport.java | 31 ++++++++++++------- .../boot/gradle/bundling/BootJar.java | 4 +-- .../boot/gradle/bundling/BootWar.java | 4 +-- .../gradle/bundling/BootZipCopyAction.java | 17 +++++++--- .../bundling/AbstractBootArchiveTests.java | 17 ++++++++++ 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootArchiveSupport.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootArchiveSupport.java index 99d5ef3fe4..64eb4266c7 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootArchiveSupport.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootArchiveSupport.java @@ -17,6 +17,7 @@ package org.springframework.boot.gradle.bundling; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -41,19 +42,30 @@ import org.gradle.api.tasks.util.PatternSet; */ class BootArchiveSupport { + private static final Set DEFAULT_LAUNCHER_CLASSES; + + static { + Set defaultLauncherClasses = new HashSet(); + defaultLauncherClasses.add("org.springframework.boot.loader.JarLauncher"); + defaultLauncherClasses.add("org.springframework.boot.loader.PropertiesLauncher"); + defaultLauncherClasses.add("org.springframework.boot.loader.WarLauncher"); + DEFAULT_LAUNCHER_CLASSES = Collections.unmodifiableSet(defaultLauncherClasses); + } + private final PatternSet requiresUnpack = new PatternSet(); private final Set storedPathPrefixes; private final PatternSet exclusions = new PatternSet(); - private String loaderMainClass; + private final String loaderMainClass; private LaunchScriptConfiguration launchScript = new LaunchScriptConfiguration(); private boolean excludeDevtools = true; - BootArchiveSupport(String... storedPathPrefixes) { + BootArchiveSupport(String loaderMainClass, String... storedPathPrefixes) { + this.loaderMainClass = loaderMainClass; this.storedPathPrefixes = new HashSet<>(Arrays.asList(storedPathPrefixes)); this.requiresUnpack.include(Specs.satisfyNone()); configureExclusions(); @@ -67,21 +79,18 @@ class BootArchiveSupport { CopyAction createCopyAction(Jar jar) { CopyAction copyAction = new BootZipCopyAction(jar.getArchivePath(), - jar.isPreserveFileTimestamps(), this.requiresUnpack.getAsSpec(), - this.exclusions.getAsExcludeSpec(), this.launchScript, - this.storedPathPrefixes); + jar.isPreserveFileTimestamps(), isUsingDefaultLoader(jar), + this.requiresUnpack.getAsSpec(), this.exclusions.getAsExcludeSpec(), + this.launchScript, this.storedPathPrefixes); if (!jar.isReproducibleFileOrder()) { return copyAction; } return new ReproducibleOrderingCopyAction(copyAction); } - String getLoaderMainClass() { - return this.loaderMainClass; - } - - void setLoaderMainClass(String loaderMainClass) { - this.loaderMainClass = loaderMainClass; + private boolean isUsingDefaultLoader(Jar jar) { + return DEFAULT_LAUNCHER_CLASSES + .contains(jar.getManifest().getAttributes().get("Main-Class")); } LaunchScriptConfiguration getLaunchScript() { diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java index f0af0aed7f..9665c0f8aa 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootJar.java @@ -35,14 +35,14 @@ import org.gradle.api.tasks.bundling.Jar; */ public class BootJar extends Jar implements BootArchive { - private BootArchiveSupport support = new BootArchiveSupport("BOOT-INF/lib"); + private BootArchiveSupport support = new BootArchiveSupport( + "org.springframework.boot.loader.JarLauncher", "BOOT-INF/lib"); private FileCollection classpath; private String mainClass; public BootJar() { - this.support.setLoaderMainClass("org.springframework.boot.loader.JarLauncher"); CopySpec bootInf = getRootSpec().addChildBeforeSpec(getMainSpec()) .into("BOOT-INF"); bootInf.into("lib", classpathFiles(File::isFile)); diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java index 59c96290b8..8203ffa6fc 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootWar.java @@ -36,7 +36,8 @@ import org.gradle.api.tasks.bundling.War; */ public class BootWar extends War implements BootArchive { - private final BootArchiveSupport support = new BootArchiveSupport("WEB-INF/lib/", + private final BootArchiveSupport support = new BootArchiveSupport( + "org.springframework.boot.loader.WarLauncher", "WEB-INF/lib/", "WEB-INF/lib-provided"); private String mainClass; @@ -44,7 +45,6 @@ public class BootWar extends War implements BootArchive { private FileCollection providedClasspath; public BootWar() { - this.support.setLoaderMainClass("org.springframework.boot.loader.WarLauncher"); getWebInf().into("lib-provided", (copySpec) -> { copySpec.from((Callable>) () -> { return this.providedClasspath == null ? Collections.emptyList() diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootZipCopyAction.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootZipCopyAction.java index a49efae2b0..348f352d4e 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootZipCopyAction.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/bundling/BootZipCopyAction.java @@ -53,6 +53,8 @@ class BootZipCopyAction implements CopyAction { private final boolean preserveFileTimestamps; + private final boolean includeDefaultLoader; + private final Spec requiresUnpack; private final Spec exclusions; @@ -62,10 +64,12 @@ class BootZipCopyAction implements CopyAction { private final Set storedPathPrefixes; BootZipCopyAction(File output, boolean preserveFileTimestamps, - Spec requiresUnpack, Spec exclusions, - LaunchScriptConfiguration launchScript, Set storedPathPrefixes) { + boolean includeDefaultLoader, Spec requiresUnpack, + Spec exclusions, LaunchScriptConfiguration launchScript, + Set storedPathPrefixes) { this.output = output; this.preserveFileTimestamps = preserveFileTimestamps; + this.includeDefaultLoader = includeDefaultLoader; this.requiresUnpack = requiresUnpack; this.exclusions = exclusions; this.launchScript = launchScript; @@ -79,7 +83,7 @@ class BootZipCopyAction implements CopyAction { FileOutputStream fileStream = new FileOutputStream(this.output); writeLaunchScriptIfNecessary(fileStream); zipStream = new ZipOutputStream(fileStream); - writeLoaderClasses(zipStream); + writeLoaderClassesIfNecessary(zipStream); } catch (IOException ex) { throw new GradleException("Failed to create " + this.output, ex); @@ -102,8 +106,13 @@ class BootZipCopyAction implements CopyAction { }; } - private void writeLoaderClasses(ZipOutputStream out) { + private void writeLoaderClassesIfNecessary(ZipOutputStream out) { + if (this.includeDefaultLoader) { + writeLoaderClasses(out); + } + } + private void writeLoaderClasses(ZipOutputStream out) { ZipEntry entry; try (ZipInputStream in = new ZipInputStream(getClass() .getResourceAsStream("/META-INF/loader/spring-boot-loader.jar"))) { diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/bundling/AbstractBootArchiveTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/bundling/AbstractBootArchiveTests.java index ce7a164a11..876b98d511 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/bundling/AbstractBootArchiveTests.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/bundling/AbstractBootArchiveTests.java @@ -135,6 +135,20 @@ public abstract class AbstractBootArchiveTests { } } + @Test + public void loaderIsWrittenToTheRootOfTheJarWhenUsingThePropertiesLauncher() + throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.execute(); + this.task.getManifest().getAttributes().put("Main-Class", + "org.springframework.boot.loader.PropertiesLauncher"); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry( + "org/springframework/boot/loader/LaunchedURLClassLoader.class")) + .isNotNull(); + } + } + @Test public void unpackCommentIsAddedToEntryIdentifiedByAPattern() throws IOException { this.task.setMainClass("com.example.Main"); @@ -207,6 +221,9 @@ public abstract class AbstractBootArchiveTests { .isEqualTo("com.example.CustomLauncher"); assertThat(jarFile.getManifest().getMainAttributes().getValue("Start-Class")) .isEqualTo("com.example.Main"); + assertThat(jarFile.getEntry( + "org/springframework/boot/loader/LaunchedURLClassLoader.class")) + .isNull(); } }