138

I have a code base which I want to distribute as jar. It also have dependency on external jars, which I want to bundle in the final jar.

I heard that this can be done using maven-assembly-plug-in, but I don't understand how. Could someone point me to some examples.

Right now, I'm using fat jar to bundle the final jar. I want to achieve the same thing using maven.

OneCricketeer
  • 151,199
  • 17
  • 111
  • 216
bianca
  • 6,676
  • 12
  • 40
  • 56

6 Answers6

171

Note: If you are a spring-boot application, read the end of answer

Add following plugin to your pom.xml The latest version can be found at

...
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>CHOOSE LATEST VERSION HERE</version>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>assemble-all</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
...

After configuring this plug-in, running mvn package will produce two jars: one containing just the project classes, and a second fat jar with all dependencies with the suffix "-jar-with-dependencies".

if you want correct classpath setup at runtime then also add following plugin

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

For spring boot application use just following plugin (choose appropriate version of it)

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <configuration>
        <fork>true</fork>
        <mainClass>${start-class}</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>
forkdbloke
  • 1,403
  • 2
  • 11
  • 29
jmj
  • 232,312
  • 42
  • 391
  • 431
  • 1
    Current version of this plugin is now 2.4 – guerda Nov 12 '13 at 15:28
  • 18
    This is now deprecated and the maven-shade-plugin should be used instead. See @phlogratos answer: http://stackoverflow.com/a/16222965/274350. – Richard Neish Sep 05 '14 at 09:22
  • 2
    Can maven-assembly-plugin minimize size of fat jar? – May12 Dec 04 '15 at 05:25
  • what do you mean by minimizing size of fat jar ? @May12 – jmj Dec 04 '15 at 05:26
  • Automatcally excluding unusable dependencies from jar. I read that this function is supported in maven-shadow plugin. But i use assembly plugin and i decided to ask. – May12 Dec 04 '15 at 05:29
  • 1
    @Richard Where do you see it is deprecated ? I couldn't find anything around here http://maven.apache.org/plugins/maven-assembly-plugin/ – user3833308 Mar 12 '18 at 23:52
  • @May assembly allows you to hand pick what goes in jar. not sure about automatic detection. – user3833308 Mar 12 '18 at 23:54
  • 3
    @user3833308 "deprecated" may be the wrong word, but the documentation at https://maven.apache.org/plugins/maven-assembly-plugin/ says "If your project wants to package your artifact in an uber-jar, the assembly plugin provides only basic support. For more control, use the Maven Shade Plugin." – Richard Neish Mar 13 '18 at 10:25
  • 1
    The repackage goal of the spring-boot-maven-plugin may also be used simply to package a JAR with nested dependencies with `layout=NONE`. This doesn't require the project to use spring or spring boot. https://docs.spring.io/spring-boot/docs/current/maven-plugin/reference/html/#goals – Derek Cochran Jun 13 '20 at 00:13
  • similar issue: https://stackoverflow.com/questions/70833195/spring-boot-multi-module-spring-boot-maven-plugin-compilation-failure/70833786#70833786 – emoleumassi Jan 24 '22 at 13:21
65

You can use the maven-shade-plugin.

After configuring the shade plugin in your build the command mvn package will create one single jar with all dependencies merged into it.

Community
  • 1
  • 1
phlogratos
  • 12,089
  • 1
  • 30
  • 37
  • 12
    This is now the correct way to do it. The maven-assembly-plugin documentation states: "If your project wants to package your artifact in an uber-jar, the assembly plugin provides only basic support. For more control, use the Maven Shade Plugin." – Richard Neish Sep 05 '14 at 09:20
  • But how do I take that single .jar and use it for publishing? – DanGordon Jun 05 '18 at 20:00
  • 1
    I disagree that this is now the "correct" way to do it. if you just want basic behaviour then you can absolutely continue to use the assembly plugin. the shade plugin does advanced stuff like rewriting the bytecode to modify package names of dependencies, once you start getting into that with production code you are introducing additional risk which is not worth it if you don't have a good reason. – Adam Burley Jul 29 '21 at 13:36
50

Maybe you want maven-shade-plugin, bundle dependencies, minimize unused code and hide external dependencies to avoid conflicts.

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.1.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <minimizeJar>true</minimizeJar>
                        <createDependencyReducedPom>true</createDependencyReducedPom>
                        <dependencyReducedPomLocation>
                            ${java.io.tmpdir}/dependency-reduced-pom.xml
                        </dependencyReducedPomLocation>
                        <relocations>
                            <relocation>
                                <pattern>com.acme.coyote</pattern>
                                <shadedPattern>hidden.coyote</shadedPattern>
                            </relocation>
                        </relocations>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

References:

Patrick Favre
  • 31,961
  • 9
  • 105
  • 121
ggrandes
  • 1,977
  • 21
  • 16
  • If one encounters `Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found`, just remove `true`. – koppor Sep 06 '17 at 10:21
  • If you get an "java.lang.SecurityException: Invalid signature file digest for Manifest main attributes" exception, then this addition to the above configuration section helps: https://stackoverflow.com/a/6743609/38368 – Danny Varod May 16 '18 at 14:29
14

actually, adding the

<archive>
   <manifest>
    <addClasspath>true</addClasspath>
    <packageName>com.some.pkg</packageName>                     
    <mainClass>com.MainClass</mainClass>
  </manifest>
</archive>

declaration to maven-jar-plugin does not add the main class entry to the manifest file for me. I had to add it to the maven-assembly-plugin in order to get that in the manifest

Faisal Feroz
  • 11,886
  • 4
  • 37
  • 51
ameet chaubal
  • 1,310
  • 13
  • 37
5

You can use the onejar-maven-plugin for packaging. Basically, it assembles your project and its dependencies in as one jar, including not just your project jar file, but also all external dependencies as a "jar of jars", e.g.

<build>
    <plugins>
        <plugin>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
                <version>1.4.4</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>one-jar</goal>
                        </goals>
                    </execution>
                </executions>
        </plugin>
    </plugins>
</build>

Note 1: Configuration options is available at the project home page.

Note 2: For one reason or the other, the onejar-maven-plugin project is not published at Maven Central. However jolira.com tracks the original project and publishes it to with the groupId com.jolira.

matsev
  • 29,504
  • 14
  • 112
  • 148
  • Is it possible to choose dependencies that you want to package with? For example, if a.jar and b.jar are external jars and I want to package only a.jar into final jar, is it something possible/configurable? – bianca Apr 25 '13 at 21:36
  • I also see one-jar stuff got bundled in final jar too. This increased size of the final jar a lot. Is it possible to choose external jars that you intend to include in final jar? Here is the one-jar logs: http://pastebin.com/UwniQJ2X – bianca Apr 25 '13 at 21:52
  • I don't know if you can configure what is included or not. Basically, one-jar includes all dependencies that are specified by your project, including transitive dependencies, so yes, the final jar is likely to become big if you have a lot of dependencies. Some overhead will be added by one-jar, in order to get Java working with the "jar of jars" structure. – matsev Apr 26 '13 at 13:09
2

An alternative is to use the maven shade plugin to build an uber-jar.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <version> Your Version Here </version>
    <configuration>
            <!-- put your configurations here -->
    </configuration>
    <executions>
            <execution>
                    <phase>package</phase>
                    <goals>
                            <goal>shade</goal>
                    </goals>
            </execution>
    </executions>
</plugin>
Stanislav
  • 2,496
  • 1
  • 27
  • 38