Maven: Packaging dependencies alongside project JAR?
Solution 1
I've like Maven to package a project with run-time dependencies.
This part is unclear (it's not exactly what you describe just after). My answer covers what you described.
I expect it to create a JAR file with the following manifest (...)
Configure the Maven Jar Plugin to do so (or more precisely, the Maven Archiver):
<project>
...
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.acme.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
...
<dependencies>
<dependency>
<groupId>dependency1</groupId>
<artifactId>dependency1</artifactId>
<version>X.Y</version>
</dependency>
<dependency>
<groupId>dependency2</groupId>
<artifactId>dependency2</artifactId>
<version>W.Z</version>
</dependency>
</dependencies>
...
</project>
And this will produce a MANIFEST.MF with the following entries:
...
Main-Class: fully.qualified.MainClass
Class-Path: lib/dependency1-X.Y.jar lib/dependency2-W.Z.jar
...
and create the following directory structure (...)
This is doable using the Maven Dependency Plugin and the dependency:copy-dependencies
goal. From the documentation:
dependency:copy-dependencies
takes the list of project direct dependencies and optionally transitive dependencies and copies them to a specified location, stripping the version if desired. This goal can also be run from the command line.
You could bind it on the package
phase:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
[...]
</project>
Solution 2
Add the following plugins in pom.xml. Check the value at mainClass,classpathPrefix,addClasspath tags.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<mainClass>org.apache.camel.spring.Main</mainClass>
<classpathPrefix>lib/</classpathPrefix>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>src/assembly/some-assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Create some-assembly.xml under src/assembly as below.
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>distribution</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<scope>runtime</scope>
<outputDirectory>/lib</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
Note that useProjectArtifact flag to false, unpack flag to false. If root folder inside zip file is not required,then one can make includeBaseDirectory to false.
This will create name-version-distribution.zip file. Inside zip file, there will be folder name-version. Inside this folder, your executable jar and lib folder containing all dependency jars will be present. Check manifest.MF file of executable jar. It contains both main class and classpath information.
Related videos on Youtube
Comments
-
Gili over 3 years
I'd like Maven to package a project alongside its run-time dependencies. I expect it to create a JAR file with the following manifest:
..... Main-Class : com.acme.MainClass Class-Path : lib/dependency1.jar lib/dependency2.jar .....
and create the following directory structure:
target |-- .... |-- my-project.jar |-- lib |-- dependency1.jar |-- dependency2.jar
Meaning, I want the main JAR to exclude any dependencies and I want all transitive dependencies to get copied into a "lib" sub-directory. Any ideas?
-
Skarab over 13 yearsYou can also maven assembly plugin: maven.apache.org/plugins/maven-assembly-plugin
-
Gili over 13 yearsHow do I get the maven-assembly-plugin to store the dependency JAR files alongside (as opposed to inside) my-project.jar?
-
Skarab over 13 yearsSee this page - maven.apache.org/plugins/maven-assembly-plugin/examples/single/…. Personally, I use the maven-ant-run plugin (wbarczynski.org/wp/wp-content/pom.xml_2.txt) to copy jars around but it can be done also using "pure" maven.
-
Devanshu Mevada over 13 years@Gilli Well, the
dependency:copy-dependencies
has aclassifier
optional parameter and my guess is that you have a${classifier}
property defined somewhere in your POM. In any case, that's specific to your project. -
Gili over 13 years@Pascal, is there a way to tell "copy-dependencies" to pretend classifier is not set even if it's set elsewhere in the POM?
-
Devanshu Mevada over 13 years@Gilli I don't think so. The obvious suggestion would be to change the name of the property to avoid this collision. Or, use
dependency:copy
and list explicitly the dependencies that you want (of course, this might induce lots of duplication). -
Gili over 13 yearsI ended up removing the use of a classifier in the POM. That fixed it. Thanks!
-
Martin over 13 yearsI had to use a different output directory to make it work: “<outputDirectory>${project.build.directory}/classes/lib</outputDirectory>” Thanks for the answer (and the question)!
-
Devanshu Mevada over 13 years@Martin Weird, the above just works (tested) if you want to get the jars in
target/lib
. Of course, if you want another location, you'll have to change theoutputDirectory
. But that's another story. -
Sahil Dave over 10 yearsEven after specifying the above config for dependency plugin I get all the jars in the default 'dependency' folder. And on packaging 'MANIFEST.MF' has the main class and classpath, but no dependency jars are packaged in the final jar.
-
Gili over 9 years@SahilDave Maybe it wasn't clear, but
no dependency jars are packaged in the final jar
is by design. When I posted this question, I wanted the dependencies stored outside the main JAR. -
Stefan Falk almost 9 yearsI have tried this (see this question) but I am getting the error "Artifact has not been packaged yet. When used on reactor artifact, copy should be executed after packaging: see MDEP-187.". What could be the problem? :/
-
asgs about 7 yearsexcellent! does this only copy the dependencies marked with scope runtime?