28

I'm trying to create a executable jar(using maven) that contains the project classes and it's dependencies with a manifest file that has the entry for the main class and the class path entry that points to the dependencies packed in the root of the jar;something like this :

Manifest File:

.....
Main-Class : com.acme.MainClass
Class-Path : dependecy1.jar dependecy2.jar
.....

Jar:

jar-root
|-- ....
|-- com/acme/../*.class
|-- dependecy1.jar
`-- dependecy2.jar

I'm using the maven-jar-plugin to create the manifest file and the maven-shade-plugin to create the "uber" jar but the dependencies are unpacked and added as classes to my jar.

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
please delete me
  • 295
  • 1
  • 3
  • 6

4 Answers4

61

Actually, I didn't check what the maven-shade-plugin is doing exactly (or any other plugin) as maven 2 has everything built-in to create a megajar or uberjar. You just have to use the maven-assembly-plugin with the predefined jar-with-dependencies descriptor.

Just add this snippet to your pom.xml to customize the manifest:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>my.package.to.my.MainClass</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

And the following command will generate your uberjar:

mvn assembly:assembly -DdescriptorId=jar-with-dependencies

But, again, the default behavior of this descriptor is to unpack dependencies (like the maven-shade-plugin). To be honest, I don't get why this is a problem but, if this is really not what you want, you can use your own custom assembly descriptor.

To do so, first, create your assembly descriptor, let's say src/assembly/uberjar.xml, with the following content:

<assembly>
  <id>uberjar</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <unpack>false</unpack>
      <scope>runtime</scope>
      <useProjectArtifact>false</useProjectArtifact>
    </dependencySet>
  </dependencySets>
  <fileSets>
    <fileSet>
      <directory>${project.build.outputDirectory}</directory>
      <outputDirectory>/</outputDirectory>
    </fileSet>
  </fileSets>
</assembly>

Then, configure the maven-assembly-plugin to use this descriptor and to add the dependencies to the Class-Path entry of the manifest:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <descriptors> 
      <descriptor>src/assembly/uberjar.xml</descriptor>
    </descriptors>
    <archive>
      <manifest>
        <mainClass>my.package.to.my.MainClass</mainClass>
        <addClasspath>true</addClasspath>
      </manifest>
    </archive>
  </configuration>
  <!--
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
  -->
</plugin>

Finally run mvn assembly:assembly to produce your uberjar.

Optionally, uncomment the executions element to bind the assembly plugin on the package phase (and have the assembly produced as part of the normal build).

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 4
    +1, awesomely helpful answer. I could imagine that some software producers, especially outside of OS, may forbid "disassembling/reverse engineering" their product, or insist their packaging be maintained as-is, including the file name, etc. – Carl Smotricz Dec 04 '09 at 08:53
  • 2
    assembly:assembly has been replaced by assembly:single recently. (i am on assembly-plugin version 2.3) – Hans Westerbeek Oct 08 '12 at 13:57
  • assembly plugin is a plugin just like shade plugin, so it is not "build in" – Krzysztof Krasoń May 15 '16 at 14:41
  • Hello,I have a library added to the project by pon (OpenCV), when I run I get an error of missing library dependencies so I would like to generate the jar of this library and its dependencies and add it to my project through this method. ? – Hérick Raposo Sep 29 '22 at 20:53
6

OneJar has a maven2 plugin.

skaffman
  • 398,947
  • 96
  • 818
  • 769
2

I've used FatJar for this in the past. http://fjep.sourceforge.net/

I had created a relatively simple application, the client was going to want to double click on an executable and have it just work. Installers or dependencies are out of the question. Fatjar bundled up the project libraries and referenced files from Eclipse into a several megabyte executable jar for me. Flawless.

Karl
  • 8,967
  • 5
  • 29
  • 31
  • Is this an Eclipse plugin? If so, I don't see how it answers the question. The OP is asking for a maven solution... – Pascal Thivent Dec 02 '09 at 18:37
  • You're right, I misread that part. I guess I was thinking that it could be applied to other areas, since all IDEs are little more than wrappers of wrappers of scripts. – Karl Dec 02 '09 at 18:52
0
task uberJar(type: Jar) {
    manifest {
        attributes 'Main-Class': 'main.RunTest'
    }
    dependsOn configurations.runtimeClasspath
    from sourceSets.main.output
    from sourceSets.test.output
    from sourceSets.main.resources
    from sourceSets.test.resources
    from {
        configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
    }
    from {
        project(':someothermoudule').sourceSets.main.resources // If current project depends on some other modules
        project(':someothermoudule').sourceSets.test.resources // If current project depends on some other modules
    }
    exclude 'META-INF/*.RSA'
    exclude 'META-INF/*.SF'
    exclude 'META-INF/*.DSA'
}

In case of gradle above can help. Note the from { project('')} lines, this is only required when the current project depends on some other sub projects or modules.

Priyanshu
  • 3,040
  • 3
  • 27
  • 34
  • I have the same problem. I want to build the Maven project with eclipse. My question is: in which file and where do you save the following: ``` org.apache.maven.plugins maven-assembly-plugin ... --> ``` I am also trying to generate `uberjar.xml` file. – m.i.cosacak Apr 03 '21 at 22:49
  • Here is my question on githib: https://github.com/tensorflow/java/issues/273 – m.i.cosacak Apr 03 '21 at 22:59
  • After several trying; it has to be between ` ... ` in `pom.xml` file – m.i.cosacak Apr 04 '21 at 01:28