Including Dependencies in a Jar With Maven

Including dependencies in a jar with Maven

You can do this using the maven-assembly plugin with the "jar-with-dependencies" descriptor. Here's the relevant chunk from one of our pom.xml's that does this:

  <build>
<plugins>
<!-- any other plugins -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>

How can I create an executable JAR with dependencies using Maven?


<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>

and you run it with

mvn clean compile assembly:single

Compile goal should be added before assembly:single or otherwise the code on your own project is not included.

See more details in comments.


Commonly this goal is tied to a build phase to execute automatically. This ensures the JAR is built when executing mvn install or performing a deployment/release.

<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>fully.qualified.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

How to add local jar files to a Maven project?

Install the JAR into your local Maven repository (typically .m2 in your home folder) as follows:

mvn install:install-file \
-Dfile=<path-to-file> \
-DgroupId=<group-id> \
-DartifactId=<artifact-id> \
-Dversion=<version> \
-Dpackaging=<packaging> \
-DgeneratePom=true

Where each refers to:

<path-to-file>: the path to the file to load e.g → c:\kaptcha-2.3.jar

<group-id>: the group that the file should be registered under e.g → com.google.code

<artifact-id>: the artifact name for the file e.g → kaptcha

<version>: the version of the file e.g → 2.3

<packaging>: the packaging of the file e.g. → jar

Reference

  • Maven FAQ: I have a jar that I want to put into my local repository. How can I copy it in?
  • Maven Install Plugin Usage: The install:install-file goal

How to include maven dependencies in a jar file?

Take a look at this question: How can I create an executable JAR with dependencies using Maven?

I think that @Rocky Inde's answer is what you are looking for (using eclipse):

1) Just right-click on your project folder (in Eclipse) and select
Export

2) Then select Java -> Runnable Jar

3) You will be asked to choose the location of the jar file

4) Finally, select the class that has the Main method that you want to
run and choose Package dependencies with the Jar file and click Finish

Maven not including dependencies in Jar file

You can verify yourself if the driver is included in the resulting artifact (supposing its name is assembly.jar):

jar tf target/assembly.jar | fgrep jdbc

It probably is, though.

I think the problem comes from the fact that the driver is automatically registered using the Service Provider Interface (SPI), by listing the classes in META-INF/services/java.sql.Driver. However, because the assembly plugin packages the dependency jars inside the assembly jar instead of exploding them and creating an uber-jar (like the shade plugin can), the SPI files are not scanned. See this blog post for example.

I suggest you try the shade plugin instead, configured with a ServicesResourceTransformer.


Update

If the SPI mechanism doesn't work in your context (jar loaded as a plugin by a container application), you can register the driver yourself if there's a place in the code you know will be called before the driver is used (some initialization service for the plugin, for example, maybe by implementing Plugin.onLoad()?): just create a instance of the driver, it will register itself.

try {
new org.neo4j.jdbc.http.HttpDriver();
} catch (SQLException e) {
logger.error("Could not load HttpDriver for Neo4j", e);
}

How to bundle a JAR file with its dependencies using maven

Sounds like you need to use the "maven-assembly-plugin" with the "jar-with-dependencies" descriptor.

E.g. here is a full example pom file with a dependency on ByteBuddy:

<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>test.example</groupId>
<artifactId>packaging-example</artifactId>
<version>1.0-SNAPSHOT</version>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>test.example.TestByteBuddy</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

</plugins>
</build>

<dependencies>

<dependency>
<groupId>net.bytebuddy</groupId>
<artifactId>byte-buddy</artifactId>
<version>1.12.6</version>
</dependency>

</dependencies>

</project>

And for the sake of completeness - here is the main class also :

package test.example;

import net.bytebuddy.ByteBuddy;

public class TestByteBuddy
{
public static void main(String... args) throws Exception
{
System.out.println("Hello Byte Buddy Class - " + ByteBuddy.class);
}
}

Building this will produce an additional file in the target directory - packaging-example-1.0-SNAPSHOT-jar-with-dependencies.jar

Then you should be able to run it simply with :

java -jar packaging-example-1.0-SNAPSHOT-jar-with-dependencies.jar 

to give you the output:

Hello Byte Buddy Class - class net.bytebuddy.ByteBuddy

Generate jar file in Maven with dependencies and tests

My solution is to build an archive (zip or other formats) that contains your classes in a jar, the dependencies jars, a folder with runtime configuration files and scripts to launch the application. The scope is to have a run ready application just by unzipping the archive.

The built archive content is:

artifactId-version.zip:
<artifactId folder>
├─ config
| ├─ log4j2.xml
├─ lib
| ├─ <all dependencies jars>
├─ leanft.cmd
├─ leanft.sh
└─ artifactId-version.jar

You should tailor the solution based on what/if you need configuration files. You don't need the META-INF folders with MANIFEST.MF files because will be generated automatically by maven plugin.

Project structure

<maven_module_root>
├─ src
| ├─ main
| | ├─ assembly
| | | ├─ leanft-assembly.xml
| | ├─ java
| | | ├─ <your classes content>
| | ├─ resources
| | | ├─ log4j2.xml
| | | ├─ <your runtime configuration files>
| | ├─ scripts
| | | ├─ leanft.cmd
| | | ├─ leanft.sh
│ └───test
├─ pom.xml

The project structure is similar with your current structure with two additional folders:

- assembly: in this folder is the leanft-assembly.xml to customize the maven-assembly-plugin.

- scripts: in this folder are the launcher scripts for your application. This is necessary it if you need to have runtime configuration files available for edit. In my example, the resources/log4j2.xml will be in a config file so the user can edit this file without touching any jar/archive.

Assembly descriptor

The solution is based on maven assembly plugin with custom configuration. I recommend to get familiar with it, starting with descriptor assembly descriptor

Your leanft-assembly.xml could look like:

<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>dist</id>
<formats>
<!-- <format>tar.gz</format> -->
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<baseDirectory>${project.artifactId}</baseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}/lib</directory>
<outputDirectory>/lib</outputDirectory>
<includes>
<include>*.*</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/config</outputDirectory>
<includes>
<include>log4j2.xml</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/main/scripts</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>leanft.*</include>
</includes>
</fileSet>
</fileSets>
</assembly>

Maven pom

Finally, the pom.xml make use of 3 plugins:

    <plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<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>test.LeanFTest</mainClass>
</manifest>
</archive>
<excludes>
<exclude>log4j2.xml</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/leanft-assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>

I will explain the usage of maven plugins:

- maven-dependency-plugin: copy all dependencies at package phase in a lib folder under the target folder.

- maven-jar-plugin:

    - archive: generate manifest file, define in manifest all dependencies from the lib folder and what is the main class so you can run the application also with "java -jar"

    - excludes: don't include the log4j2.xml file in the module jar because will be in config folder available at runtime from outside jar.

- maven-assembly-plugin: create at package phase a zip file that contains your distribution. The archive is placed in target folder. The descriptor tag reference your assembly configuration file leanft-assembly.xml.

Script

The script to launch the application call java with predefined parameters, the main line from script being:

%JAVA_HOME%\bin\java %JVM_ARGS% -cp %SCRIPT_DIR%\*;%SCRIPT_DIR%\config\ test.LeanFTest

How to generate a JAR with Maven and 3rd party dependencies

It depends on how GestorProblema1maquina.jar was built. Does GestorProblema1maquina.jar contain the 3rd party jar with dominio/Instancia class, as in, is it a fat jar / uber jar?

If it is built using maven assembly plugin in a way that it includes all of its dependencies, you should not run into this at runtime.

There are 2 choices

  1. Use mvn install and make GestorProblema1maquina.jar available in the repository.
  2. [link] https://maven.apache.org/plugins/maven-dependency-plugin/copy-dependencies-mojo.html says that the dependecnies are copied from a repository.

Also it states "The scopes being interpreted are the scopes as Maven sees them, not as specified in the pom" , so your configuration for the plugin may need explicit includes for the 3rd party system scope jar dependency to be included in the eventual jar.



Related Topics



Leave a reply



Submit