English 中文(简体)
Is it possible to create an "uber" jar containing the project classes and the project dependencies as jars with a custom manifest file?
原标题:

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.

最佳回答

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

问题回答

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.

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.





相关问题
Spring Properties File

Hi have this j2ee web application developed using spring framework. I have a problem with rendering mnessages in nihongo characters from the properties file. I tried converting the file to ascii using ...

Logging a global ID in multiple components

I have a system which contains multiple applications connected together using JMS and Spring Integration. Messages get sent along a chain of applications. [App A] -> [App B] -> [App C] We set a ...

Java Library Size

If I m given two Java Libraries in Jar format, 1 having no bells and whistles, and the other having lots of them that will mostly go unused.... my question is: How will the larger, mostly unused ...

How to get the Array Class for a given Class in Java?

I have a Class variable that holds a certain type and I need to get a variable that holds the corresponding array class. The best I could come up with is this: Class arrayOfFooClass = java.lang....

SQLite , Derby vs file system

I m working on a Java desktop application that reads and writes from/to different files. I think a better solution would be to replace the file system by a SQLite database. How hard is it to migrate ...

热门标签