Include Maven dependencies in .jar
All in one .jar
It is practical to have a single executable file to run your application, but what if it uses a lot of dependencies? Well, you can include them inside the .jar with a handy Maven plugin.
Creating the Maven project
Let's start by creating the Maven project with:
mvn archetype:generate -DgroupId=dev.ralphdeving -DartifactId=quick-sqlite -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
The pom.xml and Java 9+
Now we have to modify the pom.xml according to the Maven docs to target the java version we are using (11 this time).
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<!-- Other Maven plugins here -->
</plugins>
</pluginManagement>
</build>
Dependencies
For this example we are going to create a simple Hello, World! with SQLite, so we add it to the dependencies:
<dependencies>
<!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.36.0.3</version>
</dependency>
</dependencies>
Java Code
The SQLite example is just going to create an in-memory database, create a table and insert and read the records.
package dev.ralphdeving;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
public class QuickSQLite {
public static void main(String[] args) {
try (Connection conn = DriverManager.getConnection("jdbc:sqlite::memory:");) {
Statement stmt = conn.createStatement();
stmt.execute("CREATE TABLE IF NOT EXISTS the_table (id INTEGER PRIMARY KEY, data_column TEXT NOT NULL);");
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO the_table(data_column) VALUES(?);");
pstmt.setString(1, "Some data here.");
pstmt.executeUpdate();
ResultSet rs = stmt.executeQuery("SELECT id, data_column FROM the_table;");
while (rs.next()) {
System.out.println("[" + rs.getInt("id") + "] " + rs.getString("data_column"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
maven-assembly-plugin
Now it's time to put the maven-assembly-plugin on the pom.xml and there are a few points worth noting:
- The plugin must be declared at
build > plugins
and NOT inbuild > pluginManagement > plugins
. - You must specify the main class for the .jar to be executable.
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>dev.ralphdeving.QuickSQLite</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<!-- ... -->
</plugins>
</pluginManagement>
</build>
Package and Execute
Using mvn package
on our project, we'll get a .jar named <project-name>-<version>-jar-with-dependencies.jar
that if we inspect its contents, we'll notice that the dependencies were unpackaged and copied to the new .jar.
Now we just use java -jar <project-name>-<version>-jar-with-dependencies.jar
without worrying of the location of the dependencies.