Building an executable jar file with maven-jar-plugin is fairly easy. However, it has one disadvantage that the Maven dependencies are not packaged together inside the resulting jar file but have to be stored separately on the file system and added to the class path. Often it is not an issue but sometimes you may want to create a single self-contained jar file which does not depend on anything external. Below you can find an example how to do it.
Consider we have a very simple application with main method:
package com.example.runnablejar; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import org.apache.commons.codec.digest.DigestUtils; public class Main { public static void main(String[] args) throws IOException { if (args.length == 0) { System.err.println("Usage: cryptohash file1 ..."); return; } for (String arg : args) { Path file = Paths.get(arg); calculateSha256CommonsIO2(file); } } private static void calculateSha256CommonsIO2(Path path) throws IOException { try (InputStream is = Files.newInputStream(path)) { String hashString = DigestUtils.sha256Hex(is); System.out.printf("SHA256(%s) = %s%n", path, hashString); } } }
This application uses Apache Commons Codec library which is distributed as a separate jar file. Storing this jar file inside our application jar file would not work because it would not be present on the class path.
To overcome this issue we can use maven-assembly-plugin in POM file:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>runnablejar</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>runnablejar</name> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.5.2</version> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> <configuration> <appendAssemblyId>false</appendAssemblyId> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>com.example.runnablejar.Main</mainClass> </manifest> </archive> </configuration> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.9</version> <type>jar</type> </dependency> </dependencies> </project>
Looking from the high level perspective the Apache Commons Codec jar will be merged together with our application jar and the new MANIFEST.MF file will be added:
$ jar tf runnablejar-1.0-SNAPSHOT.jar META-INF/ META-INF/MANIFEST.MF (...) org/apache/commons/codec/digest/DigestUtils.class (...) com/ com/example/ com/example/runnablejar/ com/example/runnablejar/Main.class (...)
The final application can be run using following command:
$ java -jar runnablejar-1.0-SNAPSHOT.jar
without manually downloading any dependencies and without configuring class path.
As usual you can find the source code of the example at GitHub.
Also even with Maven you can use good old export functionality in Eclipse (possibly with other IDEs as well).
But your approach is much better when you want to create a JAR file using a script or from command line.
I did not use this functionality of Eclipse before. Thank you for your feedback.
You can also take a look at Apache maven-shade-plugin. It provides the functionality to package the artifact into an uber-jar with all dependencies.
Reblogged this on Dinesh Ram Kali..