Tag Archives: github

Configure Maven pom.xml to build integrated executable .jar (fat jar)

Configuring Apache Maven to build an integrated .jar file took a little research, especially when building with NetBeans.. but it can be done with a little hand editing.

NOTE: Project using this example can be forked/pulled from: IngeniiCode/AvMet

Setting up the basic POM

My project originated as a NetBeans nbproject, but I wanted to convert it over to Maven for a variety of reasons, not the least of which was standardization. To do this I created a dummy Maven project, copied the pom.xml and reconfigured my project. There are many tutorials on that, so I won’t cover that here; but I will cover the pom.xml itself for reference to others, as well as myself.

Main Block

The entire pom.xml is bounded by this tag group:

<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> </project>
Basic Properties

This block defines the most basic properties of the application. I’m including the bounding block here one more time just for continuity / reference; even though all blocks are within this bounding block. The ellipsis ( […] ) is not part of the package.. it’s only denoting that there is more of pom than just this section.

<?xml version="1.0" encoding="UTF-8"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ingeniigroup.stratux</groupId> <artifactId>AvMet</artifactId> <version>0.1.0</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> [...] </project>
Dependencies Block

For the current iteration of this project, I am importing the JDBC library for accessing SQLite database. This is a fairly heavy-weight chunk of code (resulting jar is over 6 MB). Before using the Maven configuration, project simply included the current copy of the jar. That was OK for a Proof of Concept but, bad for security patching, and keeping updates integrated when they are released. Your own Maven version handling scheme will of course dictate when/if you define later updates.. but this will get you started.

This configuration is latest as of time time of this was originally published (2-NOV-2017).

<dependencies> <!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc --> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>3.20.0</version> </dependency> </dependencies>
The Build Configuration

Finally, the build block will determine how your jar(s) are built.

This configuration will end up generating two Jars (as of original publishing date, the version number was 0.1.0). AvMet-0.1.0.jar is the stripped Jar, and to execute will require the other supporting jars to be available in a ‘lib/’ sub directory. The other jar, AvMet.jar is the integrated (fat) executable jar.

74382 Nov 2 10:57 target/AvMet-0.1.0.jar 6708128 Nov 2 10:57 target/AvMet.jar

This build block will create those two executables. To prevent Maven from appending the string ‘jar-with-dependencies’ to your combined executable, the option ‘<appendAssemblyId>false</appendAssemblyId>’ must be defined in your build configuration.

To create an integrated (single) jar, this ‘<goals>’ block must be defined:

<goals> <goal>single</goal> </goals>

In addition, to generate a specific final jar name (such as not without the version number), the ‘<finalName>${project.name}</finalName>’ tag will enable that action.

This is what my Maven build block looks like:

<build> <plugins> <plugin> <!-- Build an executable JAR --> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> <version>3.0.2</version> <configuration> <archive> <manifest> <addClasspath>true</addClasspath> <classpathPrefix>lib/</classpathPrefix> <mainClass>com.ingeniigroup.stratux.AvMet.AvMet</mainClass> </manifest> </archive> </configuration> </plugin> <plugin> <!-- Build a *fat* executable JAR --> <artifactId>maven-assembly-plugin</artifactId> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> <configuration> <!-- tell plugin to NO addpend the descriptionRef into target filename --> <appendAssemblyId>false</appendAssemblyId> <!-- define the final assembly name --> <finalName>${project.name}</finalName> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>com.ingeniigroup.stratux.AvMet.AvMet</mainClass> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> </plugin> </plugins> </build>

Conclusion

One you have a good pom.xml setup, you can build run within NetBeans and end up with an integrated executable that will run with this simple command path:

java -jar target/AvMet-0.1.0-jar-with-dependencies.jar ../sqlite-dbs/stratux.sqlite.11-01 keepdb scrub