Skip to content

Commit 0789ff9

Browse files
author
Dave Syer
committed
Refactor to make LayoutType a true enum again
This makes the autocompletion for pom.xml and (maybe) build.gradle easier for most users, but at the cost of a slightly odd API for deriving Layout from LayoutType.
1 parent 470bf49 commit 0789ff9

File tree

10 files changed

+132
-91
lines changed

10 files changed

+132
-91
lines changed

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

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -480,9 +480,12 @@ The following configuration options are available:
480480
|The name of the custom configuration.
481481

482482
|`layout`
483-
|The type of archive, corresponding to how the dependencies are laid out inside
484-
(defaults to a guess based on the archive type). See
485-
<<build-tool-plugins-gradle-configuration-layouts,available layouts for more details>>.
483+
|The `LayoutType` of archive, corresponding to how the dependencies are laid out inside
484+
(defaults to a guess based on the archive type).
485+
486+
|`layoutFactory`
487+
|A factory for the actual `Layout` derived from the `LayoutType`. See
488+
<<build-tool-plugins-gradle-configuration-layouts,available layouts for more details>>.
486489

487490
|`requiresUnpack`
488491
|A list of dependencies (in the form "`groupId:artifactId`" that must be unpacked from
@@ -534,9 +537,9 @@ loader should be included or not. The following layouts are available:
534537
==== Using a custom layout
535538
If you have custom requirements for how to arrange the dependencies and loader classes
536539
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+
Any library which defines one or more `LayoutFactory` implementations can be added to the
541+
build script dependencies and then the layout type becomes available in the `springBoot`
542+
configuration. For example
540543

541544
[source,groovy,indent=0,subs="verbatim,attributes"]
542545
----
@@ -556,7 +559,7 @@ buildscript {
556559
}
557560
558561
springBoot {
559-
layout = 'CUSTOM'
562+
layoutFactory = new com.example.CustomLayoutFactory()
560563
}
561564
----
562565

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

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@
2626
import org.gradle.api.plugins.JavaPlugin;
2727

2828
import org.springframework.boot.gradle.buildinfo.BuildInfo;
29+
import org.springframework.boot.loader.tools.DefaultLayoutFactory;
2930
import org.springframework.boot.loader.tools.Layout;
31+
import org.springframework.boot.loader.tools.LayoutFactory;
3032
import org.springframework.boot.loader.tools.LayoutType;
3133

3234
/**
@@ -89,7 +91,12 @@ public class SpringBootPluginExtension {
8991
* the MANIFEST.MF 'Main-Class' to be PropertiesLauncher. Gradle will coerce literal
9092
* String values to the correct type.
9193
*/
92-
String layout;
94+
LayoutType layout;
95+
96+
/**
97+
* The layout factory to use to convert a layout type into an actual layout.
98+
*/
99+
LayoutFactory layoutFactory = new DefaultLayoutFactory();
93100

94101
/**
95102
* Libraries that must be unpacked from fat jars in order to run. Use Strings in the
@@ -143,10 +150,14 @@ public SpringBootPluginExtension(Project project) {
143150

144151
/**
145152
* Convenience method for use in a custom task.
153+
* @param file the file to use to guess the layout if necessary
146154
* @return the Layout to use or null if not explicitly set
147155
*/
148-
public Layout convertLayout() {
149-
return (this.layout == null ? null : LayoutType.layout(this.layout));
156+
public Layout convertLayout(File file) {
157+
if (this.layout == null) {
158+
this.layout = LayoutType.forFile(file);
159+
}
160+
return this.layoutFactory.getLayout(this.layout);
150161
}
151162

152163
public String getMainClass() {
@@ -189,14 +200,22 @@ public void setBackupSource(boolean backupSource) {
189200
this.backupSource = backupSource;
190201
}
191202

192-
public String getLayout() {
203+
public LayoutType getLayout() {
193204
return this.layout;
194205
}
195206

196-
public void setLayout(String layout) {
207+
public void setLayout(LayoutType layout) {
197208
this.layout = layout;
198209
}
199210

211+
public LayoutFactory getLayoutFactory() {
212+
return this.layoutFactory;
213+
}
214+
215+
public void setLayoutFactory(LayoutFactory layoutFactory) {
216+
this.layoutFactory = layoutFactory;
217+
}
218+
200219
public Set<String> getRequiresUnpack() {
201220
return this.requiresUnpack;
202221
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,7 @@ private void repackage(File file) {
217217
}
218218
Repackager repackager = new LoggingRepackager(file);
219219
setMainClass(repackager);
220-
if (this.extension.convertLayout() != null) {
221-
repackager.setLayout(this.extension.convertLayout());
222-
}
220+
repackager.setLayout(this.extension.convertLayout(file));
223221
repackager.setBackupSource(this.extension.isBackupSource());
224222
try {
225223
LaunchScript launchScript = getLaunchScript();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2012-2015 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.loader.tools;
18+
19+
/**
20+
* Default implementation of layout factory that looks up the enum value and maps it to a
21+
* layout from {@link Layouts}.
22+
*
23+
* @author Dave Syer
24+
*
25+
*/
26+
public class DefaultLayoutFactory implements LayoutFactory {
27+
28+
@Override
29+
public Layout getLayout(LayoutType type) {
30+
switch (type) {
31+
case JAR:
32+
return new Layouts.Jar();
33+
case WAR:
34+
return new Layouts.War();
35+
case ZIP:
36+
return new Layouts.Expanded();
37+
case MODULE:
38+
return new Layouts.Module();
39+
default:
40+
return new Layouts.None();
41+
}
42+
}
43+
44+
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
*/
2525
public interface LayoutFactory {
2626

27-
Layout getLayout();
28-
29-
String getName();
27+
Layout getLayout(LayoutType type);
3028

3129
}

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

Lines changed: 23 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,7 @@
1616

1717
package org.springframework.boot.loader.tools;
1818

19-
import java.util.HashMap;
20-
import java.util.List;
21-
import java.util.Map;
22-
23-
import org.springframework.core.io.support.SpringFactoriesLoader;
19+
import java.io.File;
2420

2521
/**
2622
* Archive layout types.
@@ -32,70 +28,53 @@ public enum LayoutType {
3228
/**
3329
* Jar Layout.
3430
*/
35-
JAR(new Layouts.Jar()),
31+
JAR,
3632

3733
/**
3834
* War Layout.
3935
*/
40-
WAR(new Layouts.War()),
36+
WAR,
4137

4238
/**
4339
* Zip Layout.
4440
*/
45-
ZIP(new Layouts.Expanded()),
41+
ZIP,
4642

4743
/**
4844
* Dir Layout.
4945
*/
50-
DIR(new Layouts.Expanded()),
46+
DIR,
5147

5248
/**
5349
* Module Layout.
5450
*/
55-
MODULE(new Layouts.Module()),
51+
MODULE,
5652

5753
/**
5854
* No Layout.
5955
*/
60-
NONE(new Layouts.None());
61-
62-
private static Map<String, Layout> customTypes;
63-
64-
private final Layout layout;
56+
NONE;
6557

66-
public Layout layout() {
67-
return this.layout;
68-
}
69-
70-
LayoutType(Layout layout) {
71-
this.layout = layout;
72-
}
7358

74-
public static Layout layout(String value) {
75-
try {
76-
return valueOf(value).layout();
59+
/**
60+
* Return a layout type for the given source file.
61+
* @param file the source file
62+
* @return a {@link Layout}
63+
*/
64+
public static LayoutType forFile(File file) {
65+
if (file == null) {
66+
throw new IllegalArgumentException("File must not be null");
7767
}
78-
catch (IllegalArgumentException e) {
79-
if (customTypes == null) {
80-
customTypes = new HashMap<String, Layout>();
81-
lookupCustomTypes();
82-
}
83-
Layout layout = customTypes.get(value);
84-
if (layout == null) {
85-
throw new IllegalArgumentException(
86-
"Cannot resolve custom layout type: " + value);
87-
}
88-
return layout;
68+
if (file.getName().toLowerCase().endsWith(".jar")) {
69+
return JAR;
8970
}
90-
}
91-
92-
private static void lookupCustomTypes() {
93-
ClassLoader classLoader = LayoutType.class.getClassLoader();
94-
List<LayoutFactory> factories = SpringFactoriesLoader
95-
.loadFactories(LayoutFactory.class, classLoader);
96-
for (LayoutFactory factory : factories) {
97-
customTypes.put(factory.getName(), factory.getLayout());
71+
if (file.getName().toLowerCase().endsWith(".war")) {
72+
return WAR;
73+
}
74+
if (file.isDirectory() || file.getName().toLowerCase().endsWith(".zip")) {
75+
return ZIP;
9876
}
77+
throw new IllegalArgumentException("Unable to deduce layout for '" + file + "'");
9978
}
10079

10180
}

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

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,7 @@ private Layouts() {
4747
* @return a {@link Layout}
4848
*/
4949
public static Layout forFile(File file) {
50-
if (file == null) {
51-
throw new IllegalArgumentException("File must not be null");
52-
}
53-
if (file.getName().toLowerCase().endsWith(".jar")) {
54-
return new Jar();
55-
}
56-
if (file.getName().toLowerCase().endsWith(".war")) {
57-
return new War();
58-
}
59-
if (file.isDirectory() || file.getName().toLowerCase().endsWith(".zip")) {
60-
return new Expanded();
61-
}
62-
throw new IllegalStateException("Unable to deduce layout for '" + file + "'");
50+
return new DefaultLayoutFactory().getLayout(LayoutType.forFile(file));
6351
}
6452

6553
/**

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

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,28 +26,26 @@
2626
*/
2727
public class LayoutTypeTests {
2828

29+
private LayoutFactory factory = new DefaultLayoutFactory();
30+
2931
@Test
3032
public void standardType() {
31-
assertThat(LayoutType.layout("DIR"))
32-
.isEqualTo(LayoutType.valueOf("DIR").layout());
33+
assertThat(this.factory.getLayout(LayoutType.DIR)).isNotNull();
3334
}
3435

3536
@Test
3637
public void customType() {
37-
assertThat(LayoutType.layout("CUSTOM")).isNotNull();
38+
this.factory = new TestLayoutFactory();
39+
assertThat(this.factory.getLayout(LayoutType.MODULE)).isNotNull();
3840
}
3941

4042
public static class TestLayoutFactory implements LayoutFactory {
4143

4244
@Override
43-
public Layout getLayout() {
45+
public Layout getLayout(LayoutType type) {
4446
return new Layouts.Jar();
4547
}
4648

47-
@Override
48-
public String getName() {
49-
return "CUSTOM";
50-
}
5149
}
5250

5351
}

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

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
import org.apache.maven.shared.artifact.filter.collection.ScopeFilter;
4242

4343
import org.springframework.boot.loader.tools.DefaultLaunchScript;
44+
import org.springframework.boot.loader.tools.DefaultLayoutFactory;
4445
import org.springframework.boot.loader.tools.LaunchScript;
46+
import org.springframework.boot.loader.tools.LayoutFactory;
4547
import org.springframework.boot.loader.tools.LayoutType;
4648
import org.springframework.boot.loader.tools.Libraries;
4749
import org.springframework.boot.loader.tools.Repackager;
@@ -130,7 +132,14 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
130132
* @since 1.0
131133
*/
132134
@Parameter
133-
private String layout;
135+
private LayoutType layout;
136+
137+
/**
138+
* The type of the layout factory that converts layout type to an actual layout.
139+
* @since 1.0
140+
*/
141+
@Parameter
142+
private LayoutFactory layoutFactory = new DefaultLayoutFactory();
134143

135144
/**
136145
* A list of the libraries that must be unpacked from fat jars in order to run.
@@ -225,9 +234,15 @@ private File getTargetFile() {
225234
private Repackager getRepackager(File source) {
226235
Repackager repackager = new LoggingRepackager(source, getLog());
227236
repackager.setMainClass(this.mainClass);
228-
if (this.layout != null) {
229-
getLog().info("Layout: " + this.layout);
230-
repackager.setLayout(LayoutType.layout(this.layout));
237+
if (this.layout == null) {
238+
this.layout = LayoutType.forFile(source);
239+
}
240+
getLog().info("Layout: " + this.layout);
241+
try {
242+
repackager.setLayout(this.layoutFactory.getLayout(this.layout));
243+
}
244+
catch (Exception e) {
245+
throw new IllegalStateException("Cannot create layout", e);
231246
}
232247
return repackager;
233248
}

0 commit comments

Comments
 (0)