Morgan Stanley's Application plugin for Gradle allows you to package your Java-based applications for distribution, much like Gradle's built-in Application plugin does, but in a more standard and more flexible way.
The fundamental difference between the two is how the application gets packaged: while Gradle's built-in plugin generates a start script that can run the correct java -cp myApp.jar:... my.app.Main
command for the user, this plugin goes back to the Java standard ways for packaging applications, and generates an application JAR that the user can simply execute via the command java -jar myApp.jar
.
Other than that, this plugin is very much like Gradle's: it applies the Java and Distribution plugins the same way, and also requires only a single piece of configuration: the name of the main class.
- Uses Java's standard approach to packaging applications
- Platform-independent: no OS-specific start scripts
- Less code to understand / maintain
- Less complexity
- You can write the final
java
command any way you like- No need to tunnel any options / flags into the command through environment variables
- To customize the command further, you don't need to understand and override built-in defaults
- Clean handling of dependencies
- Nicely structured
lib
directory that contains the original dependency JARs in an easily recognizable layout - Easy to tell where loaded classes came from (which dependency JAR)
- No JAR merging issues (forcing everything into a single fat JAR can lead to problems when multiple dependency JARs happen to contain a file at the same path, e.g. the Shadow plugin requires special configuration to correctly merge files like
META-INF/spring.factories
) - Works with standard class loaders (unlike Spring Boot Executable JARs that have a few restrictions)
- Retains the order of dependencies on the classpath, as they got resolved by Gradle (unlike the
-cp lib/*
approach)
- Nicely structured
- No command length issue on Windows (forget the dreaded
The input line is too long
error) - Switching from Gradle's built-in Application plugin is a breeze
To use this plugin:
- Modify your
build.gradle[.kts]
file (see examples below)- Apply the plugin via the
plugins {}
block - Configure your application(s) using the
applications
extension
- Apply the plugin via the
- Run the tasks defined by the Distribution plugin to build your application(s)
- If you're not familiar with those tasks, read the Usage section of the Distribution plugin's documentation
The plugin adds an extension named applications
to the project, which is a container of Application
objects. It also creates a single application in the applications
container named main
. If your build only produces one application, you only need to configure this main
application; setting the mainClass
property should be enough in most cases.
// build.gradle
plugins {
id "com.ms.gradle.application" version "2.0.2"
}
applications.main {
mainClass = "my.app.Main"
}
For more complex examples, see the build file of the plugin's functional test.
// build.gradle.kts
plugins {
id("com.ms.gradle.application").version("2.0.2")
}
applications.main {
mainClass.set("my.app.Main")
}
For more complex examples, see the build file of the plugin's functional test.
Application JARs generated by this plugin are an exact copy of the artifact built by another Jar
task, with the two necessary headers, Class-Path
and Main-Class
added to META-INF/MANIFEST.MF
. By default, the JAR is written to $buildDir/application
(directory and file names are customizable).
Each application JAR then gets added to a distribution, together with a lib
directory containing all the dependency artifacts. Each artifact will be copied to lib/$group/$artifact
, which is also how the Class-Path
header will refer to them, using relative URLs.
<distribution>
├── lib
│ ├── com.google.code.gson
│ │ └── gson-2.10.jar
│ └── org.slf4j
│ ├── slf4j-api-2.0.3.jar
│ └── slf4j-simple-2.0.3.jar
└── myApp.jar
The actual application distributions get assembled and written to disk by the Distribution plugin's tasks.
The main
application is created and configured automatically based on the main
source set. By default, it will:
- Make a modified copy of the artifact built by the built-in
jar
task - Use the dependencies defined by the built-in
runtimeClasspath
configuration
All you need to set yourself is the mainClass
property, and you're good to go!
- The plugin provides a number of settings to customize each application that gets built. For the available options, please refer to the Javadoc of the
Application
class. - If you need to build multiple applications, you can simply use the
applications
container to set them up.
This plugin was written by Denes Daniel, working for Morgan Stanley's Java Platform Engineering team.