views:

20177

answers:

10

I have written a little utility to run from the commandline. I want to package it in a single executable jar for distribution.

How can I make maven package all dependend jars into my jar?

+27  A: 
<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 assembly:assembly
01
thanks for the effort of replacing the brackets
soemirno
Post XML using <element>
laz
@laz: no need to. Just post it as regular code (i.e. with 4 spaces intendation on each line)
Joachim Sauer
I'm really not sure this answer is correct. See http://stackoverflow.com/questions/1814526/problem-building-executable-jar-with-maven
Pascal Thivent
I'm trying to do the same thing as the OP, but this isn't working for me :(
James.Elsey
+10  A: 

Taking Unanswered's answer and reformatting it, we have:

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

Next, I would recommend making this a natural part of your build, rather than something to call explicitly. To make this a integral part of your build, add this plugin to your pom.xml and bind it to the package lifecycle event. However, a gotcha is that you need to call the assembly:single goal if putting this in your pom.xml, while you would call 'assembly:assembly' if executing it manually from the command line.

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
        <executions>
          <execution>
            <id>make-my-jar-with-dependencies</id>
            <phase>package</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      [...]
    </plugins>
    [...]
  </build>
</project>
Matthew McCullough
Using the approach in this answer results in the following error message: 'Failed to load Main-Class manifest attribute from <jar file>', when trying to run the JAR using 'java -jar <jar file>'
Elmo
A: 

shorter answer: the maven Dependency plugin is designed for this.

Ken Liu
Please explain which goal of the dependency plugin you are referring to. I know of no goal which does what the original question requests: to put all the dependencies either A) inside the authors jar via repackaging, or B) make an executable jar that has the others in a classpath of MANIFEST.MF
Matthew McCullough
+2  A: 

Another option if you really want to repackage the other JARs contents inside your single resultant JAR is the Maven Assembly plugin. It unpacks and then repacks everything into a directory via <unpack>true</unpack>. Then you'd have a second pass that built it into one massive JAR.

Another option is the OneJar plugin. This performs the above repackaging actions all in one step.

Matthew McCullough
+1  A: 

Ken Liu has it right in my opinion. The maven dependency plugin allows you to expand all the dependencies, which you can then treat as resources. This allows you to include them in the main artifact. The use of the assembly plugin creates a secondary artifact which can be difficult to modify - in my case I wanted to add custom manifest entries. My pom ended up as:

<project>
 ...
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>unpack-dependencies</id>
      <phase>package</phase>
      <goals>
       <goal>unpack-dependencies</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
  ...
  <resources>
   <resource>
    <directory>${basedir}/target/dependency</directory>
    <targetPath>/</targetPath>
   </resource>
  </resources>
 </build>
 ...
</project>
Matthew Franglen
+1  A: 

You can use maven-dependency-plugin, but the question was how to create an executable JAR. To do that requires the following alteration to Matthew Franglen's response (btw, using the dependency plugin takes longer to build when starting from a clean target):

<build>
 <plugins>
  <plugin>
   <artifactId>maven-jar-plugin</artifactId>
   <configuration>
    <archive>
     <manifest>
      <mainClass>fully.qualified.MainClass</mainClass>
     </manifest>
    </archive>
   </configuration>
  </plugin>
  <plugin>
   <artifactId>maven-dependency-plugin</artifactId>
   <executions>
    <execution>
     <id>unpack-dependencies</id>
     <phase>package</phase>
     <goals>
      <goal>unpack-dependencies</goal>
     </goals>
    </execution>
   </executions>
  </plugin>
 </plugins>
 <resources>
  <resource>
   <directory>${basedir}/target/dependency</directory>
  </resource>
 </resources>
</build>
Will Hoover
+1  A: 

I won't answer directly the question as other have already done that before, but I really wonder if it's a good idea to embed all the dependencies in the project's jar itself.

I see the point (ease of deployment / usage) but it depends of the use case of your poject (and there may be alternatives (see below)).

If you use it fully standalone, why not.

But if you use your project in other contexts (like in a webapp, or dropped in a folder where other jars are sitting), you may have jar duplicates in your classpath (the ones in the folder, the one in the jars). Maybe not a bid deal but i usually avoid this.

A good alternative :

  • deploy your application as a .zip / .war : the archive contains your project's jar and all dependent jars ;
  • use a dynamic classloader mechanism (see Spring, or you can easily do this yourself) to have a single entry point of your project (a single class to start - see the Manifest mechanism on another answer), which will add (dynamically) to the current classpath all the other needed jars.

Like this, with in the end just a manifest and a "special dynamic classloader main", you can start your project with :

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass
Sergio
A: 

it should be like that

    <plugin>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                        <execution>
                                <id>unpack-dependencies</id>
                                <phase>generate-resources</phase>
                                <goals>
                                        <goal>unpack-dependencies</goal>
                                </goals>
                        </execution>
                </executions>
        </plugin>

unpacking have to be in generate-resources phase because, if in package phase, will not be included as resources. Try clean package and you'll see

kac-ani
+1  A: 

If you want if from command Line itself . Just run the below command from the project path

mvn assembly:assembly

Mayank
+3  A: 

Use the maven-shade-plugin to package all dependencies into one uber-jar. It can also be used to build an executable jar by specifying the main class. After trying to use maven-assembly and maven-jar , I found that this plugin best suited my needs.

I found this plugin particularly useful as it merges content of specific files instead of overwriting them. This is needed when there are resource files that are have the same name across the jars and the plugin tries to package all the resource files

See example below

      <plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                           implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>
Vijay Katam
So how does bcprov-jdk15.jar get onto the classpath at runtime, given that it's excluded from the shading process?
Andrew Swan
It was getting pulled by cxf-rt-ws-security which is part of my dependencies
Vijay Katam