diff --git a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc index 6b662acd1a..55449e04e6 100644 --- a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc +++ b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc @@ -493,7 +493,7 @@ The following configuration options are available: [[build-tool-plugins-gradle-configuration-layouts]] -==== Available layouts +==== Available built-in layouts The `layout` attribute configures the format of the archive and whether the bootstrap loader should be included or not. The following layouts are available: @@ -530,6 +530,37 @@ loader should be included or not. The following layouts are available: +[[build-tool-plugins-gradle-configuration-custom-layout]] +==== Using a custom layout +If you have custom requirements for how to arrange the dependencies and loader classes +inside the repackaged jar, you can use a custom layout in addition to the built-in values. +Any library which defines one or more `LayoutFactory` implementations and +lists them in `META-INF/spring.factories` can be added to the build script dependencies +and then the layout type becomes available in the `springBoot` configuration. For example + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- +buildscript { + ext { + springBootVersion = '1.5.0.BUILD-SNAPSHOT' + customVersion = '0.0.1.BUILD-SNAPSHOT' + } + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath("com.example:custom-layout:${customVersion}") + classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") + } +} + +springBoot { + layout = 'CUSTOM' +} +---- + + [[build-tool-plugins-understanding-the-gradle-plugin]] === Understanding how the Gradle plugin works When `spring-boot` is applied to your Gradle project a default task named `bootRepackage` diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java index 9b250d9cbc..d84bb2134c 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java @@ -20,6 +20,8 @@ import java.io.File; import java.util.Map; import java.util.Set; +import groovy.lang.Closure; + import org.gradle.api.Project; import org.gradle.api.plugins.JavaPlugin; @@ -27,8 +29,6 @@ import org.springframework.boot.gradle.buildinfo.BuildInfo; import org.springframework.boot.loader.tools.Layout; import org.springframework.boot.loader.tools.LayoutType; -import groovy.lang.Closure; - /** * Gradle DSL Extension for 'Spring Boot'. Most of the time Spring Boot can guess the * settings in this extension, but occasionally you might need to explicitly set one or diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java index d5a05dd094..929ef645dc 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java @@ -53,8 +53,6 @@ import org.springframework.lang.UsesJava7; */ public class JarWriter { - private static final String NESTED_LOADER_JAR = "META-INF/loader/spring-boot-loader.jar"; - private static final int BUFFER_SIZE = 32 * 1024; private final JarOutputStream jarOutput; @@ -206,9 +204,20 @@ public class JarWriter { /** * Write the required spring-boot-loader classes to the JAR. * @throws IOException if the classes cannot be written + * @deprecated us {@link #writeLoaderClasses(String)} instead */ + @Deprecated public void writeLoaderClasses() throws IOException { - URL loaderJar = getClass().getClassLoader().getResource(NESTED_LOADER_JAR); + writeLoaderClasses(Layouts.DEFAULT_LOADER_JAR); + } + + /** + * Write the required spring-boot-loader classes to the JAR. + * @param loaderJarPath the path to the loader jar (in the classpath) + * @throws IOException if the classes cannot be written + */ + public void writeLoaderClasses(String loaderJarPath) throws IOException { + URL loaderJar = getClass().getClassLoader().getResource(loaderJarPath); JarInputStream inputStream = new JarInputStream( new BufferedInputStream(loaderJar.openStream())); JarEntry entry; diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java index 38681e107e..09f7ded6be 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java @@ -40,15 +40,25 @@ public interface Layout { String getLibraryDestination(String libraryName, LibraryScope scope); /** - * Returns the location of classes within the archive. + * Returns the location of classes within the archive. Empty if the location is the + * root path, otherwise ends with a slash ('/'). * @return the classes location */ String getClassesLocation(); /** - * Returns if loader classes should be included to make the archive executable. + * Returns if loader classes should be included to make the archive executable. If + * true, then {@link #getLoaderJarPath()} should point to a valid jar file that + * contains the loader classes. * @return if the layout is executable */ boolean isExecutable(); + /** + * Returns the path to a nested jar that contains the loader, and which will be + * unpacked into the root of the repackaged jar. + * @return the path to a nested jar that contains the loader + */ + String getLoaderJarPath(); + } diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutFactory.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutFactory.java index 66c5738f86..9b21eceeb3 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutFactory.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutFactory.java @@ -18,14 +18,14 @@ package org.springframework.boot.loader.tools; /** * Strategy for creating instances of {@link Layout}. - * + * * @author Dave Syer * */ public interface LayoutFactory { - + Layout getLayout(); - + String getName(); } diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutType.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutType.java index ff101007fe..6901a21117 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutType.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutType.java @@ -24,6 +24,8 @@ import org.springframework.core.io.support.SpringFactoriesLoader; /** * Archive layout types. + * + * @author Dave Syer */ public enum LayoutType { diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java index 3cebdc7a05..992a6ab40e 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java @@ -33,6 +33,11 @@ import java.util.Set; */ public final class Layouts { + /** + * Default value for {@link #getLoaderJarPath()}. + */ + public static final String DEFAULT_LOADER_JAR = "META-INF/loader/spring-boot-loader.jar"; + private Layouts() { } @@ -87,6 +92,11 @@ public final class Layouts { return true; } + @Override + public String getLoaderJarPath() { + return DEFAULT_LOADER_JAR; + } + } /** @@ -116,6 +126,11 @@ public final class Layouts { return false; } + @Override + public String getLoaderJarPath() { + return DEFAULT_LOADER_JAR; + } + } /** @@ -154,6 +169,11 @@ public final class Layouts { return true; } + @Override + public String getLoaderJarPath() { + return DEFAULT_LOADER_JAR; + } + } /** @@ -188,6 +208,11 @@ public final class Layouts { return false; } + @Override + public String getLoaderJarPath() { + return DEFAULT_LOADER_JAR; + } + } } diff --git a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java index c25129844b..757ece7071 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java @@ -217,7 +217,7 @@ public class Repackager { } writeNestedLibraries(standardLibraries, seen, writer); if (this.layout.isExecutable()) { - writer.writeLoaderClasses(); + writer.writeLoaderClasses(this.layout.getLoaderJarPath()); } } finally { diff --git a/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutTypeTests.java b/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutTypeTests.java index 5fc5135419..3792529f22 100644 --- a/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutTypeTests.java +++ b/spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutTypeTests.java @@ -28,14 +28,15 @@ public class LayoutTypeTests { @Test public void standardType() { - assertThat(LayoutType.layout("DIR")).isEqualTo(LayoutType.valueOf("DIR").layout()); + assertThat(LayoutType.layout("DIR")) + .isEqualTo(LayoutType.valueOf("DIR").layout()); } @Test public void customType() { assertThat(LayoutType.layout("CUSTOM")).isNotNull(); } - + public static class TestLayoutFactory implements LayoutFactory { @Override @@ -46,6 +47,7 @@ public class LayoutTypeTests { @Override public String getName() { return "CUSTOM"; - }} + } + } } diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java index 2e07cba4a0..42de1700b4 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java +++ b/spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java @@ -227,6 +227,7 @@ public class RepackageMojo extends AbstractDependencyFilterMojo { repackager.setMainClass(this.mainClass); if (this.layout != null) { getLog().info("Layout: " + this.layout); + repackager.setLayout(LayoutType.layout(this.layout)); } return repackager; } diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/custom-layout.apt.vm b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/custom-layout.apt.vm new file mode 100644 index 0000000000..031e29ff71 --- /dev/null +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/examples/custom-layout.apt.vm @@ -0,0 +1,57 @@ + ----- + Use a custom layout + ----- + Dave Syer + ----- + 2016-10-30 + ----- + + Spring Boot repackages the jar file for this project using a custom + layout defined in the additional jar file, provided as a dependency + to the build plugin: + +--- + + ... + + ... + + ... + + ${project.groupId} + ${project.artifactId} + ${project.version} + + + + repackage + + + CUSTOM + + + + + + com.example + custom-layout + 0.0.1.BUILD-SNAPSHOT + + + ... + + ... + + ... + + ... + +--- + + The layout is provided as an implementation of <> + (from spring-boot-loader-tools) listed in + <> inside the <> jar. + + + + diff --git a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt index dcf5084405..cb767f9e64 100644 --- a/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt +++ b/spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt @@ -48,6 +48,8 @@ Spring Boot Maven Plugin * {{{./examples/repackage-disable-attach.html}Local repackaged artifact}} + * {{{./examples/custom-layout.html}Custom layout}} + * {{{./examples/exclude-dependency.html}Exclude a dependency}} * {{{./examples/run-debug.html}Debug the application}}