Including dependencies in a jar with Maven

JavaMaven 2JarPackaging

Java Problem Overview


Is there a way to force maven(2.0.9) to include all the dependencies in a single jar file?

I have a project the builds into a single jar file. I want the classes from dependencies to be copied into the jar as well.

Update: I know that I cant just include a jar file in a jar file. I'm searching for a way to unpack the jars that are specified as dependencies, and package the class files into my jar.

Java Solutions


Solution 1 - Java

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>

Solution 2 - Java

With Maven 2, the right way to do this is to use the Maven2 Assembly Plugin which has a pre-defined descriptor file for this purpose and that you could just use on the command line:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

If you want to make this jar executable, just add the main class to be run to the plugin configuration:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>my.package.to.my.MainClass</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

If you want to create that assembly as part of the normal build process, you should bind the single or directory-single goal (the assembly goal should ONLY be run from the command line) to a lifecycle phase (package makes sense), something like this:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <id>create-my-bundle</id>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
        ...
      </configuration>
    </execution>
  </executions>
</plugin>

Adapt the configuration element to suit your needs (for example with the manifest stuff as spoken).

Solution 3 - Java

If you want to do an executable jar file, them need set the main class too. So the full configuration should be.

    <plugins>
            <plugin>
                 <artifactId>maven-assembly-plugin</artifactId>
                 <executions>
                     <execution>
                          <phase>package</phase>
                          <goals>
                              <goal>single</goal>
                          </goals>
                      </execution>
                  </executions>
                  <configuration>
                       <!-- ... -->
                       <archive>
                           <manifest>
                                 <mainClass>fully.qualified.MainClass</mainClass>
                           </manifest>
                       </archive>
                       <descriptorRefs>
                           <descriptorRef>jar-with-dependencies</descriptorRef>
                      </descriptorRefs>
                 </configuration>
         </plugin>
   </plugins>

Solution 4 - Java

There's the shade maven plugin. It can be used to package and rename dependencies (to omit dependency problems on the classpath).

Solution 5 - Java

        <!-- Method 1 -->
        <!-- Copy dependency libraries jar files to a separated LIB folder -->
		<plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <excludeTransitive>false</excludeTransitive> 
                <stripVersion>false</stripVersion>
            </configuration>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <!-- Add LIB folder to classPath -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                    </manifest>
                </archive>
            </configuration>
        </plugin>


        <!-- Method 2 -->
        <!-- Package all libraries classes into one runnable jar -->
        <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>            

Solution 6 - Java

You can use the newly created jar using a <classifier> tag.

<dependencies>
    <dependency>
        <groupId>your.group.id</groupId>
        <artifactId>your.artifact.id</artifactId>
        <version>1.0</version>
        <type>jar</type>
        <classifier>jar-with-dependencies</classifier>
    </dependency>
</dependencies>

Solution 7 - Java

If you (like me) dont particularly like the jar-with-dependencies approach described above, the maven-solution I prefer is to simply build a WAR-project, even if it is only a stand-alone java application you are building:

  1. Make a normal maven jar-project, that will build your jar-file (without the dependencies).

  2. Also, setup a maven war-project (with only an empty src/main/webapp/WEB-INF/web.xml file, which will avoid a warning/error in the maven-build), that only has your jar-project as a dependency, and make your jar-project a <module> under your war-project. (This war-project is only a simple trick to wrap all your jar-file dependencies into a zip-file.)

  3. Build the war-project to produce the war-file.

  4. In the deployment-step, simply rename your .war-file to *.zip and unzip it.

You should now have a lib-directory (which you can move where you want it) with your jar and all the dependencies you need to run your application:

java -cp 'path/lib/*' MainClass

(The wildcard in classpath works in Java-6 or higher)

I think this is both simpler to setup in maven (no need to mess around with the assembly plugin) and also gives you a clearer view of the application-structure (you will see the version-numbers of all dependent jars in plain view, and avoid clogging everything into a single jar-file).

Solution 8 - Java

http://fiji.sc/Uber-JAR provides an excellent explanation of the alternatives:

> There are three common methods for constructing an uber-JAR: > > 1. Unshaded. Unpack all JAR files, then repack them into a single JAR.

  • Pro: Works with Java's default class loader.
  • Con: Files present in multiple JAR files with the same path (e.g., > META-INF/services/javax.script.ScriptEngineFactory) will overwrite one > another, resulting in faulty behavior.
  • Tools: Maven Assembly > Plugin, Classworlds Uberjar > 1. Shaded. Same as unshaded, but rename (i.e., "shade") all packages of all dependencies.
  • Pro: Works with Java's default class loader. > Avoids some (not all) dependency version clashes.
  • Con: Files > present in multiple JAR files with the same path (e.g., > META-INF/services/javax.script.ScriptEngineFactory) will overwrite one > another, resulting in faulty behavior.
  • Tools: Maven Shade Plugin > 1. JAR of JARs. The final JAR file contains the other JAR files embedded within.
  • Pro: Avoids dependency version clashes. All > resource files are preserved.
  • Con: Needs to bundle a special > "bootstrap" classloader to enable Java to load classes from the > wrapped JAR files. Debugging class loader issues becomes more complex. > * Tools: Eclipse JAR File Exporter, One-JAR.

Solution 9 - Java

My definitive solution on Eclipse Luna and m2eclipse: Custom Classloader (download and add to your project, 5 classes only) :http://git.eclipse.org/c/jdt/eclipse.jdt.ui.git/plain/org.eclipse.jdt.ui/jar%20in%20jar%20loader/org/eclipse/jdt/internal/jarinjarloader/; this classloader is very best of one-jar classloader and very fast;

<project.mainClass>org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader</project.mainClass> <project.realMainClass>my.Class</project.realMainClass>

Edit in JIJConstants "Rsrc-Class-Path" to "Class-Path"
mvn clean dependency:copy-dependencies package
is created a jar with dependencies in lib folder with a thin classloader

<build>
	<resources>
		<resource>
			<directory>src/main/java</directory>
			<includes>
				<include>**/*.java</include>
				<include>**/*.properties</include>
			</includes>
		</resource>
		<resource>
			<directory>src/main/resources</directory>
			<filtering>true</filtering>
			<includes>
				<include>**/*</include>
			</includes>
			<targetPath>META-INF/</targetPath>
		</resource>
		<resource>
			<directory>${project.build.directory}/dependency/</directory>
			<includes>
				<include>*.jar</include>
			</includes>
			<targetPath>lib/</targetPath>
		</resource>
	</resources>
<pluginManagement>
		<plugins>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<configuration>
					<archive>
						<manifest>
							<addClasspath>true</addClasspath>
							<mainClass>${project.mainClass}</mainClass>
							<classpathPrefix>lib/</classpathPrefix>
						</manifest>

						<manifestEntries>
							<Rsrc-Main-Class>${project.realMainClass}  </Rsrc-Main-Class>
							<Class-Path>./</Class-Path>
						</manifestEntries>

					</archive>
				</configuration>
			</plugin>
<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-dependency-plugin</artifactId>
				<executions>
					<execution>
						<id>copy-dependencies</id>
						<phase>package</phase>
						<goals>
							<goal>copy-dependencies</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</pluginManagement>
</build>

Solution 10 - Java

Putting Maven aside, you can put JAR libraries inside the Main Jar but you will need to use your own classloader.

Check this project: One-JAR link text

Solution 11 - Java

Thanks I have added below snippet in POM.xml file and Mp problem resolved and create fat jar file that include all dependent jars.

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
	    <executions>
		    <execution>
			    <phase>package</phase>
				<goals>
				    <goal>single</goal>
		        </goals>
		    </execution>
		</executions>
	    <configuration>
		    <descriptorRefs>
			    <descriptorRef>dependencies</descriptorRef>
			</descriptorRefs>
		</configuration>
	</plugin>
</plugins>

Solution 12 - Java

I was trying to do sth similar, but I didn't want all jars to be included. I wanted to include some specific directories from the given dependency. In addition classifier tag was already occupied, so I couldn't do:

<dependencies>
    <dependency>
        <groupId>your.group.id</groupId>
        <artifactId>your.artifact.id</artifactId>
        <version>1.0</version>
        <type>jar</type>
        <classifier>jar-with-dependencies</classifier>
    </dependency>
</dependencies>
  1. I used maven-dependency-plugin and unpack goal
  2. And unpacked what I wanted to the ${project.build.directory}/classes, otherwise it will be omitted
  3. Because it was in the classes directory, maven finally placed it in the jar
<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-dependency-plugin</artifactId>
	<executions>
		<execution>
			<id>unpack</id>
			<phase>prepare-package</phase>
			<goals>
				<goal>unpack</goal>
			</goals>
			<configuration>
				<artifactItems>
					<artifactItem>
						<groupId>my.group</groupId>
						<artifactId>my.artifact</artifactId>
                        <classifier>occupied</classifier>
						<version>1.0</version>
						<type>jar</type>
					</artifactItem>
				</artifactItems>
				<outputDirectory>${project.build.directory}/classes</outputDirectory>
				<includes>aaa/**, bbb/**, ccc/**</includes>
			</configuration>
		</execution>
	</executions>
</plugin>

Solution 13 - Java

This post may be a bit old, but I also had the same problem recently. The first solution proposed by John Stauffer is a good one, but I had some problems as I am working this spring. The spring's dependency-jars I use have some property files and xml-schemas declaration which share the same paths and names. Although these jars come from the same versions, the jar-with-dependencies maven-goal was overwriting theses file with the last file found.

In the end, the application was not able to start as the spring jars could not find the correct properties files. In this case the solution propose by Rop have solved my problem.

Also since then, the spring-boot project now exist. It has a very cool way to manage this problem by providing a maven goal which overload the package goal and provide its own class loader. See spring-boots Reference Guide

Solution 14 - Java

Have a look at this answer:

I am creating an installer that runs as a Java JAR file and it needs to unpack WAR and JAR files into appropriate places in the installation directory. The dependency plugin can be used in the package phase with the copy goal and it will download any file in the Maven repository (including WAR files) and write them where ever you need them. I changed the output directory to ${project.build.directory}/classes and then end result is that the normal JAR task includes my files just fine. I can then extract them and write them into the installation directory.

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
	<execution>
		<id>getWar</id>
		<phase>package</phase>
		<goals>
			<goal>copy</goal>
		</goals>
		<configuration>
			<artifactItems>
				<artifactItem>
					<groupId>the.group.I.use</groupId>
					<artifactId>MyServerServer</artifactId>
					<version>${env.JAVA_SERVER_REL_VER}</version>
					<type>war</type>
					<destFileName>myWar.war</destFileName>
				</artifactItem>
			</artifactItems>
			<outputDirectory>${project.build.directory}/classes</outputDirectory>
		</configuration>
	</execution>
</executions>

Solution 15 - Java

To make it more simple, You can use the below plugin.

             <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <classifier>spring-boot</classifier>
                            <mainClass>
                                com.nirav.certificate.CertificateUtility
                            </mainClass>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionracerView Question on Stackoverflow
Solution 1 - JavaJohn StaufferView Answer on Stackoverflow
Solution 2 - JavaPascal ThiventView Answer on Stackoverflow
Solution 3 - JavaabdielView Answer on Stackoverflow
Solution 4 - JavaThomas JungView Answer on Stackoverflow
Solution 5 - JavaLeslie LiView Answer on Stackoverflow
Solution 6 - JavalasanthaView Answer on Stackoverflow
Solution 7 - JavaRopView Answer on Stackoverflow
Solution 8 - JavaAndré Willik ValentiView Answer on Stackoverflow
Solution 9 - JavaGlaucio SouthierView Answer on Stackoverflow
Solution 10 - JavamedopalView Answer on Stackoverflow
Solution 11 - JavaRajeev RathorView Answer on Stackoverflow
Solution 12 - JavajwpolView Answer on Stackoverflow
Solution 13 - JavaFrancois GergaudView Answer on Stackoverflow
Solution 14 - JavamillebiView Answer on Stackoverflow
Solution 15 - JavaNIrav ModiView Answer on Stackoverflow