Including dependencies in a jar with Maven

2018-12-31 06:42发布

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.

13条回答
与风俱净
2楼-- · 2018-12-31 06:49

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>

查看更多
君临天下
3楼-- · 2018-12-31 06:51

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

查看更多
若你有天会懂
4楼-- · 2018-12-31 06:55

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
  2. 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
  3. 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.
查看更多
裙下三千臣
5楼-- · 2018-12-31 06:56

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

查看更多
情到深处是孤独
6楼-- · 2018-12-31 06:57
        <!-- 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>            
查看更多
素衣白纱
7楼-- · 2018-12-31 06:59

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>
查看更多
登录 后发表回答