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 76fc73250cc..7be55a9ed17 100644
--- a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc
+++ b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc
@@ -404,6 +404,10 @@ The following configuration options are available:
|===
|Name |Description
+|`enabled`
+|Boolean flag to switch the repackager off (sometimes useful if you
+want the other Boot features but not this one)
+
|`mainClass`
|The main class that should be run. If not specified the `mainClassName` project property
will be used or, if the no `mainClassName` id defined the archive will be searched for a
@@ -419,9 +423,10 @@ The following configuration options are available:
the original jar as a dependency in another project, it's best to use an extension to
define the executable archive.
-|`withJarTask`
-|The name of the `Jar` task (defaults to all) which is used to locate the archive to
- repackage.
+|`withJarTask`
+|The name or value of the `Jar` task (defaults to all
+tasks of type `Jar`) which is used to locate the archive to
+repackage.
|`customConfiguration`
|The name of the custom configuration whuch is used to populate the nested lib directory
diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc
index 206e95c30cc..73db77ade18 100644
--- a/spring-boot-docs/src/main/asciidoc/howto.adoc
+++ b/spring-boot-docs/src/main/asciidoc/howto.adoc
@@ -1579,6 +1579,122 @@ See the {spring-boot-maven-plugin-site}/usage.html[plugin documentation] for ful
details.
+[[howto-create-an-additional-executable-jar]]
+=== Create an additional executable JAR
+
+If you want to use your project as a library jar for other projects to
+depend on, and in addition have an executable (e.g. demo) version of
+it, you will want to configure the build in a slightly different way.
+
+For Maven the normal JAR plugin and the Spring Boot plugin both have a
+"classifier" configuration that you can add to create an additional JAR.
+Example (using the Spring Boot Starter Parent to manage the plugin
+versions and other configuration defaults):
+
+[source,xml,indent=0,subs="verbatim,quotes,attributes"]
+----
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ exec
+
+
+
+
+----
+
+Two jars are produced, the default one, and an executable one using
+the Boot plugin with classifier "exec".
+
+For Gradle users the steps are similar. Example:
+
+[source,groovy,indent=0,subs="verbatim,attributes"]
+----
+bootRepackage {
+ classifier = 'exec'
+}
+----
+
+[[howto-create-a-nonexecutable-jar]]
+=== Create a non-executable JAR with exclusions
+
+Often if you have an executable and a non-executable jar
+as biuld products, the executable version will have additional
+configuration files that ar enot needed in a library jar. E.g. the
+`application.yml` configuration file might excluded from the
+non-executable JAR.
+
+Here's how to do that in Maven
+
+[source,xml,indent=0,subs="verbatim,quotes,attributes"]
+----
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ exec
+
+
+
+ maven-jar-plugin
+
+
+ exec
+ package
+
+ jar
+
+
+ exec
+
+
+
+ package
+
+ jar
+
+
+
+ true
+
+ application.yml
+
+
+
+
+
+
+
+----
+
+In Gradle you can create a new JAR archive with standard task DSL
+features, and then have the `bootRepackage` task depend on that one
+using its `withJarTask` property:
+
+[source,groovy,indent=0,subs="verbatim,attributes"]
+----
+jar {
+ baseName = 'spring-boot-sample-profile'
+ version = '0.0.0'
+ excludes = ['**/application.yml']
+}
+
+task('execJar', type:Jar, dependsOn: 'jar') {
+ baseName = 'spring-boot-sample-profile'
+ version = '0.0.0'
+ classifier = 'exec'
+ from sourceSets.main.output
+}
+
+bootRepackage {
+ withJarTask = tasks['execJar']
+}
+----
[[howto-remote-debug-maven-run]]
=== Remote debug a Spring Boot application started with Maven
diff --git a/spring-boot-samples/spring-boot-sample-profile/build.gradle b/spring-boot-samples/spring-boot-sample-profile/build.gradle
new file mode 100644
index 00000000000..824c59f9296
--- /dev/null
+++ b/spring-boot-samples/spring-boot-sample-profile/build.gradle
@@ -0,0 +1,56 @@
+buildscript {
+ ext {
+ springBootVersion = '1.1.2.BUILD-SNAPSHOT'
+ }
+ repositories {
+ // NOTE: You should declare only repositories that you need here
+ mavenLocal()
+ mavenCentral()
+ maven { url "http://repo.spring.io/release" }
+ maven { url "http://repo.spring.io/milestone" }
+ maven { url "http://repo.spring.io/snapshot" }
+ }
+ dependencies {
+ classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
+ }
+}
+
+apply plugin: 'java'
+apply plugin: 'eclipse'
+apply plugin: 'idea'
+apply plugin: 'spring-boot'
+
+jar {
+ baseName = 'spring-boot-sample-profile'
+ version = '0.0.0'
+ excludes = ['**/application.yml']
+}
+
+task('execJar', type:Jar, dependsOn: 'jar') {
+ baseName = 'spring-boot-sample-profile'
+ version = '0.0.0'
+ classifier = 'exec'
+ from sourceSets.main.output
+}
+
+bootRepackage {
+ withJarTask = tasks['execJar']
+}
+
+repositories {
+ // NOTE: You should declare only repositories that you need here
+ mavenLocal()
+ mavenCentral()
+ maven { url "http://repo.spring.io/release" }
+ maven { url "http://repo.spring.io/milestone" }
+ maven { url "http://repo.spring.io/snapshot" }
+}
+
+dependencies {
+ compile("org.springframework.boot:spring-boot-starter")
+ testCompile("org.springframework.boot:spring-boot-starter-test")
+}
+
+task wrapper(type: Wrapper) {
+ gradleVersion = '1.6'
+}
diff --git a/spring-boot-samples/spring-boot-sample-profile/pom.xml b/spring-boot-samples/spring-boot-sample-profile/pom.xml
index 96ee2b088eb..f1517faaff6 100644
--- a/spring-boot-samples/spring-boot-sample-profile/pom.xml
+++ b/spring-boot-samples/spring-boot-sample-profile/pom.xml
@@ -1,5 +1,6 @@
-
+
4.0.0
@@ -34,6 +35,37 @@
org.springframework.boot
spring-boot-maven-plugin
+
+ exec
+
+
+
+ maven-jar-plugin
+
+
+ exec
+ package
+
+ jar
+
+
+ exec
+
+
+
+ package
+
+ jar
+
+
+
+ true
+
+ application.yml
+
+
+
+
diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java
index f6c25fc63dd..e63879c3d68 100644
--- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java
+++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java
@@ -50,18 +50,22 @@ public class RepackagePluginFeatures implements PluginFeatures {
+ "archives so that they can be executed from the command "
+ "line using 'java -jar'");
task.setGroup(BasePlugin.BUILD_GROUP);
- task.dependsOn(project.getConfigurations()
- .getByName(Dependency.ARCHIVES_CONFIGURATION).getAllArtifacts()
- .getBuildDependencies());
+ task.dependsOn(project.getConfigurations().getByName(
+ Dependency.ARCHIVES_CONFIGURATION).getAllArtifacts().getBuildDependencies());
registerOutput(project, task);
ensureTaskRunsOnAssembly(project, task);
}
private void registerOutput(Project project, final RepackageTask task) {
project.afterEvaluate(new Action() {
+
@Override
public void execute(Project project) {
project.getTasks().withType(Jar.class, new OutputAction(task));
+ Object withJar = task.getWithJarTask();
+ if (withJar!=null) {
+ task.dependsOn(withJar);
+ }
}
});
}
@@ -74,8 +78,8 @@ public class RepackagePluginFeatures implements PluginFeatures {
* Register BootRepackage so that we can use task {@code foo(type: BootRepackage)}.
*/
private void registerRepackageTaskProperty(Project project) {
- project.getExtensions().getExtraProperties()
- .set("BootRepackage", RepackageTask.class);
+ project.getExtensions().getExtraProperties().set("BootRepackage",
+ RepackageTask.class);
}
private class OutputAction implements Action {
@@ -115,8 +119,7 @@ public class RepackagePluginFeatures implements PluginFeatures {
SpringBootPluginExtension.class);
if (task.getClassifier() != null) {
classifier = task.getClassifier();
- }
- else if (extension.getClassifier() != null) {
+ } else if (extension.getClassifier() != null) {
classifier = extension.getClassifier();
}
if (classifier != null) {
diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java
index 3306abd7028..4dc14b8d867 100644
--- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java
+++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/RepackageTask.java
@@ -53,10 +53,16 @@ public class RepackageTask extends DefaultTask {
private File outputFile;
+ private boolean enabled = true;
+
public void setCustomConfiguration(String customConfiguration) {
this.customConfiguration = customConfiguration;
}
+ public Object getWithJarTask() {
+ return withJarTask;
+ }
+
public void setWithJarTask(Object withJarTask) {
this.withJarTask = withJarTask;
}
@@ -77,6 +83,14 @@ public class RepackageTask extends DefaultTask {
this.classifier = classifier;
}
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
@TaskAction
public void repackage() {
Project project = getProject();
@@ -85,12 +99,13 @@ public class RepackageTask extends DefaultTask {
ProjectLibraries libraries = getLibraries();
project.getTasks().withType(Jar.class, new RepackageAction(extension, libraries));
}
-
+
public File[] getDependencies() {
ProjectLibraries libraries = getLibraries();
final List files = new ArrayList();
try {
libraries.doWithLibraries(new LibraryCallback() {
+
@Override
public void library(File file, LibraryScope scope) throws IOException {
files.add(file);
@@ -112,8 +127,7 @@ public class RepackageTask extends DefaultTask {
}
if (this.customConfiguration != null) {
libraries.setCustomConfigurationName(this.customConfiguration);
- }
- else if (extension.getCustomConfiguration() != null) {
+ } else if (extension.getCustomConfiguration() != null) {
libraries.setCustomConfigurationName(extension.getCustomConfiguration());
}
return libraries;
@@ -133,22 +147,30 @@ public class RepackageTask extends DefaultTask {
@Override
public void execute(Jar archive) {
+ if (!enabled) {
+ getLogger().info("Repackage disabled");
+ return;
+ }
// if withJarTask is set, compare tasks and bail out if we didn't match
if (RepackageTask.this.withJarTask != null
- && !archive.equals(RepackageTask.this.withJarTask)) {
+ && !(archive.equals(RepackageTask.this.withJarTask)
+ || archive.equals(getProject().getTasks().findByName(
+ RepackageTask.this.withJarTask.toString())))) {
+ getLogger().info(
+ "Jar task not repackaged (didn't match withJarTask): " + archive);
return;
}
- if ("".equals(archive.getClassifier())) {
+ if ("".equals(archive.getClassifier())
+ || RepackageTask.this.withJarTask != null) {
File file = archive.getArchivePath();
if (file.exists()) {
Repackager repackager = new LoggingRepackager(file);
File out = RepackageTask.this.outputFile;
- if (out != null) {
+ if (out != null && !file.equals(out)) {
try {
FileCopyUtils.copy(file, out);
- }
- catch (IOException ex) {
+ } catch (IOException ex) {
throw new IllegalStateException(ex.getMessage(), ex);
}
file = out;
@@ -161,8 +183,7 @@ public class RepackageTask extends DefaultTask {
repackager.setBackupSource(this.extension.isBackupSource());
try {
repackager.repackage(file, this.libraries);
- }
- catch (IOException ex) {
+ } catch (IOException ex) {
throw new IllegalStateException(ex.getMessage(), ex);
}
}
@@ -173,13 +194,11 @@ public class RepackageTask extends DefaultTask {
String mainClass = (String) getProject().property("mainClassName");
if (RepackageTask.this.mainClass != null) {
mainClass = RepackageTask.this.mainClass;
- }
- else if (this.extension.getMainClass() != null) {
+ } else if (this.extension.getMainClass() != null) {
mainClass = this.extension.getMainClass();
- }
- else if (getProject().getTasks().getByName("run").hasProperty("main")) {
- mainClass = (String) getProject().getTasks().getByName("run")
- .property("main");
+ } else if (getProject().getTasks().getByName("run").hasProperty("main")) {
+ mainClass = (String) getProject().getTasks().getByName("run").property(
+ "main");
}
getLogger().info("Setting mainClass: " + mainClass);
repackager.setMainClass(mainClass);
@@ -197,8 +216,7 @@ public class RepackageTask extends DefaultTask {
long startTime = System.currentTimeMillis();
try {
return super.findMainMethod(source);
- }
- finally {
+ } finally {
long duration = System.currentTimeMillis() - startTime;
if (duration > FIND_WARNING_TIMEOUT) {
getLogger().warn(