Explain Codes LogoExplain Codes Logo

Creating runnable JAR with Gradle

java
gradle
application-plugin
fat-jar
Alex KataevbyAlex Kataev·Oct 2, 2024
TLDR

To create an executable Gradle JAR, modify the build.gradle file:

jar { manifest { attributes 'Main-Class': 'com.yourapp.Main' } from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } } exclude 'path/to/excluded/files' // Make sure to bring your valid passport along! with jar }

Set 'com.yourapp.Main' to your entry point class. The command packages your JAR's manifest with a pointer to your main class while bundling runtime dependencies into a single runnable JAR. "One JAR to rule them all," if you will.

Application assembly using Gradle plugins

Getting a leg up with the Application plugin

Gradle's Application plugin simplifies the creation of a JAR. It extends tasks like installDist, distZip, and distTar which package your application and its dependencies in a neat, distributable format.

apply plugin: 'application' mainClassName = 'com.yourapp.Main' // So you want a zip or tar distribution. I got you fam! distributions { main { contents { from { 'src/main/resources' } } } }

Invoke ./gradlew installDist for a runnable directory. For compressed archives, run either ./gradlew distZip or ./gradlew distTar.

Fat JARs - When one JAR just isn't enough!

The gradle-shadow-plugin produces a fat JAR — a JAR that includes your application and all its dependencies. Introduce the plugin and use the shadowJar task as follows:

plugins { id 'com.github.johnrengelman.shadow' version 'X.X.X' } shadowJar { archiveBaseName.set('my-app') archiveVersion.set('1.0.0') manifest { attributes 'Main-Class': 'com.yourapp.Main' } }

Launch the process with ./gradlew shadowJar, culminating in my-app-1.0.0-all.jar that can be run using java -jar. Relax, the plugin's got your back!

Handy tips for manifest and resource management

Pointing the way with the Class-Path in the Manifest

There can be cases when dependencies are preferred to be outside the JAR. Use the Class-Path manifest entry for such scenarios but ensure your dependencies exist at the specified location at runtime.

jar { manifest { attributes( 'Main-Class': 'com.yourapp.Main', 'Class-Path': configurations.runtimeClasspath.files.collect { "lib/$it.name" }.join(' ') ) } from { configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { it.isDirectory() ? it : zipTree(it) } } into 'lib' }

Working with resources and excluding unnecessary files

Resources from src/main/resources/ get automatically included. Wishing to omit certain files? Here you go:

jar { // ... exclude '**/*.example', '**/*.temp' // Goodbye unnecessary files, say hi to efficiency! }

Access to resources within the JAR

To access resources within the JAR file, you can work with patterns like getClass().getResource("/path/to/resource") or ClassLoader.getSystemResource("path/to/resource").

Options for distribution

Leveraging the java-library-distribution plugin

A sturdier distribution package like a zip carrying your application's JAR and essential libraries is manageable with the java-library-distribution plugin. This places libraries in a /lib directory in the distribution, enhancing portability.

plugins { id 'java-library-distribution' } distributions { main { // Your customized configuration code comes in here } }

Stand alone with your JAR

While Gradle and the Shadow plugin render solid support for crafting executable JARs, alternative plugins like 'one-jar', 'spring-boot', and 'capsule' can likewise be considered depending on your project needs and intricacies.