An executable jar file is just a jar file containing a Main-Class entry in its manifest. So you just need to configure the jar task in order to add this entry in its manifest:
jar {
manifest {
attributes 'Main-Class': 'com.foo.bar.MainClass'
}
}
You might also need to add classpath entries in the manifest, but that would be done the same way.
See http://docs.oracle.com/javase/tutorial/deployment/jar/manifestindex.html
Both JB Nizet and Jorge_B's answers are correct.
In its simplest form, creating an executable JAR with Gradle is just a matter of adding the appropriate entries to the manifest. However, it's much more common to have dependencies that need to be included on the classpath, making this approach tricky in practice.
The application plugin provides an alternate approach; instead of creating an executable JAR, it provides:
run
task to facilitate easily running the application directly from the buildinstallDist
task that generates a directory structure including the built JAR, all of the JARs that it depends on, and a startup script that pulls it all together into a program you can rundistZip
and distTar
tasks that create archives containing a complete application distribution (startup scripts and JARs)A third approach is to create a so-called "fat JAR" which is an executable JAR that includes not only your component's code, but also all of its dependencies. There are a few different plugins that use this approach. I've included links to a few that I'm aware of; I'm sure there are more.
As others have noted, in order for a jar file to be executable, the application's entry point must be set in the Main-Class
attribute of the manifest file. If the dependency class files are not collocated, then they need to be set in the Class-Path
entry of the manifest file.
I have tried all kinds of plugin combinations and what not for the simple task of creating an executable jar and somehow someway, include the dependencies. All plugins seem to be lacking one way or another, but finally I got it like I wanted. No mysterious scripts, not a million different mini files polluting the build directory, a pretty clean build script file, and above all: not a million foreign third party class files merged into my jar archive.
The following is a copy-paste from here for your convenience..
[How-to] create a distribution zip file with dependency jars in subdirectory /lib
and add all dependencies to Class-Path
entry in the manifest file:
apply plugin: 'java'
apply plugin: 'java-library-distribution'
repositories {
mavenCentral()
}
dependencies {
compile 'org.apache.commons:commons-lang3:3.3.2'
}
// Task "distZip" added by plugin "java-library-distribution":
distZip.shouldRunAfter(build)
jar {
// Keep jar clean:
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA', 'META-INF/*.MF'
manifest {
attributes 'Main-Class': 'com.somepackage.MainClass',
'Class-Path': configurations.runtime.files.collect { "lib/$it.name" }.join(' ')
}
// How-to add class path:
// https://stackoverflow.com/questions/22659463/add-classpath-in-manifest-using-gradle
// https://gist.github.com/simon04/6865179
}
Hosted as a gist here.
The result can be found in build/distributions
and the unzipped contents look like this:
lib/commons-lang3-3.3.2.jar
MyJarFile.jar
Contents of MyJarFile.jar#META-INF/MANIFEST.mf
:
Manifest-Version: 1.0
Main-Class: com.somepackage.MainClass
Class-Path: lib/commons-lang3-3.3.2.jar
Least effort solution for me was to make use of the gradle-shadow-plugin
Besides applying the plugin all that needs to be done is:
Configure the jar task to put your Main class into manifest
jar {
manifest {
attributes 'Main-Class': 'com.my.app.Main'
}
}
Run the gradle task
./gradlew shadowJar
Take the app-version-all.jar from build/libs/
And finally execute it via:
java -jar app-version-all.jar
You can use the SpringBoot plugin:
plugins {
id "org.springframework.boot" version "2.2.2.RELEASE"
}
Create the jar
gradle assemble
And then run it
java -jar build/libs/*.jar
Note: your project does NOT need to be a SpringBoot project to use this plugin.
Have you tried the 'installApp' task? Does it not create a full directory with a set of start scripts?
http://www.gradle.org/docs/current/userguide/application_plugin.html
Thank you Konstantin, it worked like a charm with few nuances. For some reason, specifying main class as part of jar manifest did not quite work and it wanted the mainClassName attribute instead. Here is a snippet from build.gradle that includes everything to make it work:
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '1.2.2'
}
...
...
apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
...
...
mainClassName = 'com.acme.myapp.MyClassMain'
...
...
...
shadowJar {
baseName = 'myapp'
}
After running gradle shadowJar you get myapp-{version}-all.jar in your build folder which can be run as java -jar myapp-{version}-all.jar.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With