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.
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>
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.
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:
http://maven.apache.org/plugins/maven-shade-plugin/plugin-info.html
http://maven.apache.org/plugins/maven-shade-plugin/shade-mojo.html
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
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.
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>
Read if you want to use the maven-assembly-plugin.
As other answers have already outlined, it seems that the maven-shade-plugin offers more features and is the recommended plugin to build a fat jar, but in case you would like to use the maven-assembly-plugin the following plugin configuration will work.
The answer of #jmj explains that the correct classpath can be setup with an additional maven-jar-plugin, but this will only add the classpath to the original jar and not the fat jar. The information must instead be directly included into the configuration section of the maven-assembly-plugin.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.package.YourMainClass</mainClass>
</manifest>
</archive>
<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>
When you now run maven package, your normal and fat jar will be created and you can run your fat jar with java -jar yourJar.jar.
I've build this project with mvn clean install. Now I have a .jar file but I'm not able to use it with:
λ java -jar flyway-commandline-xxx.jar
no main manifest attribute, in flyway-commandline-xxx.jar
What am I missing?
An executable jar needs a "manifest file" - which is located at META-INF/MANIFEST.MF inside the jar.
You can use the Maven Assembly plugin to produce this manifest file in line with this:
...
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.5</version>
<configuration>
<archive>
<manifest>
<mainClass>dk.tbsalling.ais.cli.AisCli</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
...
The MainClass (referenced in the manifest file) is the class containing the main(...)-method called when you execute the jar.
You can have a look at https://github.com/tbsalling/aiscli/blob/master/pom.xml for a full, working example.
Use below 2 maven plugins in pom.xml:
maven-assembly-plugin with a goal to package all dependencies.
maven-jar-plugin along with this to add manifest and make jar with the dependencies included by assembly plugin.
Since, in assembly plugin below, appendAssemblyId is false, so final jar name will be with appname.jar only.
You can test assembly using command: "mvn clean compile assembly:single". (or using Jenkins JPaC file then add the command "clean compile assembly:single" under mavenGoals).
See below:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<finalName>appname</finalName>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.myorg.appname.MainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</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-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.myorg.appname.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
I want to use maven-assembly-plugin to pack external dependencies into the application's jar file. When I call mvn install it creates two jar files, one with and one without the dependencies. (appname-version.jar and appname-version-jar-with-dependencies.jar)
My question is that why it creates two jar files?
Here is the plugin: (im not using any other plugin at the moment)
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.coolapp.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>
Thank you!
You need to define the maven-jar-plugin to avoid creating the default jar. This is done by adding <phase>none</phase> under execution:
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>default-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
All the resources/classes are still moved to the target folder, so maven-assembly can still execute itself correctly.
When bulding a executable jar with the maven-assembly-plugin and afterwards running it, it is recognized as a java application.
How could I manage that the jar is listed with it's application name ?
My POM:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>package.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>
Maven gives you control over the name of your deliverable by using the finalName element, as in:
<!-- Inside your pom.xml -->
<build>
<finalName>whateverIWantToCallMyDeliverable</finalName>
</build>
May this suit you?
I use maven assembly plugin to collect all dependencies into one jar file. How can I tell maven not to repack dependencies and include them as jar files into resulting jar?
Currently I use following plugin configuration.
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>package.Program</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
wanted structure of jar file:
my-jar-with-dependencies.jar
|-dependency1.jar
|-|-class1.class
|-dependency2.jar
|-|-class2.class
|-...........
and not
my-jar-with-dependencies.jar
|-class1.class
|-class2.class
|-.............
If I understand the question correctly you want to specify when the assembly plugn should be run or not. I this is the case you should consider creating a build profile and add the assembly plugin configuration to the new profile.
In pom.xml add:
<project>
...
<profiles>
<profile>
<id>myprofile</id>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>package.Program</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
...
</project>
When you want maven to run the assembly plugin you can then use the -P switch to the 'mvn' script like this:
mvn -Pmyprofile clean package