Skip to main content

Build an Executable JAR with Maven

· 2 min read
Apache Wangye
Software developer and technical writer

A plain Maven JAR normally contains only your project's compiled classes and resources. To run it with java -jar, the archive needs a Main-Class manifest entry, and every runtime dependency must either be available on the classpath or packaged into an executable "fat" JAR.

Option 1: thin JAR with a main class​

Configure maven-jar-plugin:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>

Build it:

mvn clean verify
java -jar target/my-app-1.0.0.jar

This works only when the application has no external runtime dependencies or those dependencies are supplied separately.

Option 2: executable fat JAR with Shade​

The Maven Shade Plugin combines application classes and dependencies:

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>com.example.Main</mainClass>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

The services transformer merges META-INF/services entries used by Java's service loader. Other resource files may also require explicit merge rules.

Signed dependency errors​

Shading signed JARs can leave signature metadata that no longer matches the merged archive. If runtime verification fails with a signature error, exclude signature files:

<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>

Only do this when distributing the resulting artifact under appropriate dependency licenses and after understanding the security implications.

Verify the result​

jar tf target/my-app-1.0.0.jar | head
unzip -p target/my-app-1.0.0.jar META-INF/MANIFEST.MF
java -jar target/my-app-1.0.0.jar --help

Run integration tests against the packaged JAR, not only classes inside the Maven test process. Pin plugin versions, use a fixed Java toolchain, and avoid embedding secrets or environment-specific configuration.

For Spring Boot applications, prefer spring-boot-maven-plugin; its executable archive format and launcher handle dependencies differently from a generic shaded JAR.

Page views: --

Total views -- · Visitors --