Skip to content

Commit 470bf49

Browse files
author
Dave Syer
committed
Support for custom layout types to change loader classes
A layout can also optionally change the loader jar that is unpacked in the root of the repackaged archive by implementing a new method in Layout.
1 parent ed8bafd commit 470bf49

File tree

12 files changed

+154
-15
lines changed

12 files changed

+154
-15
lines changed

spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ The following configuration options are available:
493493

494494

495495
[[build-tool-plugins-gradle-configuration-layouts]]
496-
==== Available layouts
496+
==== Available built-in layouts
497497

498498
The `layout` attribute configures the format of the archive and whether the bootstrap
499499
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:
530530

531531

532532

533+
[[build-tool-plugins-gradle-configuration-custom-layout]]
534+
==== Using a custom layout
535+
If you have custom requirements for how to arrange the dependencies and loader classes
536+
inside the repackaged jar, you can use a custom layout in addition to the built-in values.
537+
Any library which defines one or more `LayoutFactory` implementations and
538+
lists them in `META-INF/spring.factories` can be added to the build script dependencies
539+
and then the layout type becomes available in the `springBoot` configuration. For example
540+
541+
[source,groovy,indent=0,subs="verbatim,attributes"]
542+
----
543+
buildscript {
544+
ext {
545+
springBootVersion = '1.5.0.BUILD-SNAPSHOT'
546+
customVersion = '0.0.1.BUILD-SNAPSHOT'
547+
}
548+
repositories {
549+
mavenLocal()
550+
mavenCentral()
551+
}
552+
dependencies {
553+
classpath("com.example:custom-layout:${customVersion}")
554+
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
555+
}
556+
}
557+
558+
springBoot {
559+
layout = 'CUSTOM'
560+
}
561+
----
562+
563+
533564
[[build-tool-plugins-understanding-the-gradle-plugin]]
534565
=== Understanding how the Gradle plugin works
535566
When `spring-boot` is applied to your Gradle project a default task named `bootRepackage`

spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@
2020
import java.util.Map;
2121
import java.util.Set;
2222

23+
import groovy.lang.Closure;
24+
2325
import org.gradle.api.Project;
2426
import org.gradle.api.plugins.JavaPlugin;
2527

2628
import org.springframework.boot.gradle.buildinfo.BuildInfo;
2729
import org.springframework.boot.loader.tools.Layout;
2830
import org.springframework.boot.loader.tools.LayoutType;
2931

30-
import groovy.lang.Closure;
31-
3232
/**
3333
* Gradle DSL Extension for 'Spring Boot'. Most of the time Spring Boot can guess the
3434
* settings in this extension, but occasionally you might need to explicitly set one or

spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarWriter.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@
5353
*/
5454
public class JarWriter {
5555

56-
private static final String NESTED_LOADER_JAR = "META-INF/loader/spring-boot-loader.jar";
57-
5856
private static final int BUFFER_SIZE = 32 * 1024;
5957

6058
private final JarOutputStream jarOutput;
@@ -206,9 +204,20 @@ private long getNestedLibraryTime(File file) {
206204
/**
207205
* Write the required spring-boot-loader classes to the JAR.
208206
* @throws IOException if the classes cannot be written
207+
* @deprecated us {@link #writeLoaderClasses(String)} instead
209208
*/
209+
@Deprecated
210210
public void writeLoaderClasses() throws IOException {
211-
URL loaderJar = getClass().getClassLoader().getResource(NESTED_LOADER_JAR);
211+
writeLoaderClasses(Layouts.DEFAULT_LOADER_JAR);
212+
}
213+
214+
/**
215+
* Write the required spring-boot-loader classes to the JAR.
216+
* @param loaderJarPath the path to the loader jar (in the classpath)
217+
* @throws IOException if the classes cannot be written
218+
*/
219+
public void writeLoaderClasses(String loaderJarPath) throws IOException {
220+
URL loaderJar = getClass().getClassLoader().getResource(loaderJarPath);
212221
JarInputStream inputStream = new JarInputStream(
213222
new BufferedInputStream(loaderJar.openStream()));
214223
JarEntry entry;

spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layout.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,25 @@ public interface Layout {
4040
String getLibraryDestination(String libraryName, LibraryScope scope);
4141

4242
/**
43-
* Returns the location of classes within the archive.
43+
* Returns the location of classes within the archive. Empty if the location is the
44+
* root path, otherwise ends with a slash ('/').
4445
* @return the classes location
4546
*/
4647
String getClassesLocation();
4748

4849
/**
49-
* Returns if loader classes should be included to make the archive executable.
50+
* Returns if loader classes should be included to make the archive executable. If
51+
* true, then {@link #getLoaderJarPath()} should point to a valid jar file that
52+
* contains the loader classes.
5053
* @return if the layout is executable
5154
*/
5255
boolean isExecutable();
5356

57+
/**
58+
* Returns the path to a nested jar that contains the loader, and which will be
59+
* unpacked into the root of the repackaged jar.
60+
* @return the path to a nested jar that contains the loader
61+
*/
62+
String getLoaderJarPath();
63+
5464
}

spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutFactory.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,14 @@
1818

1919
/**
2020
* Strategy for creating instances of {@link Layout}.
21-
*
21+
*
2222
* @author Dave Syer
2323
*
2424
*/
2525
public interface LayoutFactory {
26-
26+
2727
Layout getLayout();
28-
28+
2929
String getName();
3030

3131
}

spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/LayoutType.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424

2525
/**
2626
* Archive layout types.
27+
*
28+
* @author Dave Syer
2729
*/
2830
public enum LayoutType {
2931

spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Layouts.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
*/
3434
public final class Layouts {
3535

36+
/**
37+
* Default value for {@link Layout#getLoaderJarPath()}.
38+
*/
39+
public static final String DEFAULT_LOADER_JAR = "META-INF/loader/spring-boot-loader.jar";
40+
3641
private Layouts() {
3742
}
3843

@@ -87,6 +92,11 @@ public boolean isExecutable() {
8792
return true;
8893
}
8994

95+
@Override
96+
public String getLoaderJarPath() {
97+
return DEFAULT_LOADER_JAR;
98+
}
99+
90100
}
91101

92102
/**
@@ -116,6 +126,11 @@ public boolean isExecutable() {
116126
return false;
117127
}
118128

129+
@Override
130+
public String getLoaderJarPath() {
131+
return DEFAULT_LOADER_JAR;
132+
}
133+
119134
}
120135

121136
/**
@@ -154,6 +169,11 @@ public boolean isExecutable() {
154169
return true;
155170
}
156171

172+
@Override
173+
public String getLoaderJarPath() {
174+
return DEFAULT_LOADER_JAR;
175+
}
176+
157177
}
158178

159179
/**
@@ -188,6 +208,11 @@ public boolean isExecutable() {
188208
return false;
189209
}
190210

211+
@Override
212+
public String getLoaderJarPath() {
213+
return DEFAULT_LOADER_JAR;
214+
}
215+
191216
}
192217

193218
}

spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Repackager.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public void library(Library library) throws IOException {
217217
}
218218
writeNestedLibraries(standardLibraries, seen, writer);
219219
if (this.layout.isExecutable()) {
220-
writer.writeLoaderClasses();
220+
writer.writeLoaderClasses(this.layout.getLoaderJarPath());
221221
}
222222
}
223223
finally {

spring-boot-tools/spring-boot-loader-tools/src/test/java/org/springframework/boot/loader/tools/LayoutTypeTests.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ public class LayoutTypeTests {
2828

2929
@Test
3030
public void standardType() {
31-
assertThat(LayoutType.layout("DIR")).isEqualTo(LayoutType.valueOf("DIR").layout());
31+
assertThat(LayoutType.layout("DIR"))
32+
.isEqualTo(LayoutType.valueOf("DIR").layout());
3233
}
3334

3435
@Test
3536
public void customType() {
3637
assertThat(LayoutType.layout("CUSTOM")).isNotNull();
3738
}
38-
39+
3940
public static class TestLayoutFactory implements LayoutFactory {
4041

4142
@Override
@@ -46,6 +47,7 @@ public Layout getLayout() {
4647
@Override
4748
public String getName() {
4849
return "CUSTOM";
49-
}}
50+
}
51+
}
5052

5153
}

spring-boot-tools/spring-boot-maven-plugin/src/main/java/org/springframework/boot/maven/RepackageMojo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@ private Repackager getRepackager(File source) {
227227
repackager.setMainClass(this.mainClass);
228228
if (this.layout != null) {
229229
getLog().info("Layout: " + this.layout);
230+
repackager.setLayout(LayoutType.layout(this.layout));
230231
}
231232
return repackager;
232233
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
-----
2+
Use a custom layout
3+
-----
4+
Dave Syer
5+
-----
6+
2016-10-30
7+
-----
8+
9+
Spring Boot repackages the jar file for this project using a custom
10+
layout defined in the additional jar file, provided as a dependency
11+
to the build plugin:
12+
13+
---
14+
<project>
15+
...
16+
<build>
17+
...
18+
<plugins>
19+
...
20+
<plugin>
21+
<groupId>${project.groupId}</groupId>
22+
<artifactId>${project.artifactId}</artifactId>
23+
<version>${project.version}</version>
24+
<executions>
25+
<execution>
26+
<goals>
27+
<goal>repackage</goal>
28+
</goals>
29+
<configuration>
30+
<layout>CUSTOM</layout>
31+
</configuration>
32+
</execution>
33+
</executions>
34+
<dependencies>
35+
<dependency>
36+
<groupId>com.example</groupid>
37+
<artifactId>custom-layout</artifactId>
38+
<version>0.0.1.BUILD-SNAPSHOT</version>
39+
</dependency>
40+
</dependencies>
41+
...
42+
</plugin>
43+
...
44+
</plugins>
45+
...
46+
</build>
47+
...
48+
</project>
49+
---
50+
51+
The layout is provided as an implementation of <<LayoutFactory>>
52+
(from spring-boot-loader-tools) listed in
53+
<<META-INF/spring-factories>> inside the <<custom-layout>> jar.
54+
55+
56+
57+

spring-boot-tools/spring-boot-maven-plugin/src/site/apt/index.apt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ Spring Boot Maven Plugin
4848

4949
* {{{./examples/repackage-disable-attach.html}Local repackaged artifact}}
5050

51+
* {{{./examples/custom-layout.html}Custom layout}}
52+
5153
* {{{./examples/exclude-dependency.html}Exclude a dependency}}
5254

5355
* {{{./examples/run-debug.html}Debug the application}}

0 commit comments

Comments
 (0)