Include Maven dependencies in .jar

  • Home
  • -
  • Blog
  • -
  • Post
  • -
  • IncludeMavenDependencyJar
2021 . Dec . 22 / ProgrammingDatabase

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).

pom.xml
<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:

pom.xml
<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.

App.java
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 in build > pluginManagement > plugins.
  • You must specify the main class for the .jar to be executable.
pom.xml
<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.

Comments
If you have any doubt or question, or know how to improve this post, please feel free to write a comment.