views:

180

answers:

2

I've like Maven to package a project with 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

alternatively, place dependencies under a "lib" sub-directory. Any ideas?

A: 

You can use the maven jar plugin, take a look on this page: http://maven.apache.org/plugins/maven-jar-plugin/examples/manifest-customization.html

Skarab
You can also maven assembly plugin:http://maven.apache.org/plugins/maven-assembly-plugin/
Skarab
@Skarab, How do I get the maven-assembly-plugin to store the dependency JAR files alongside (as opposed to inside) my-project.jar?
Gili
See this page - http://maven.apache.org/plugins/maven-assembly-plugin/examples/single/filtering-some-distribution-files.html. Personally, I use the maven-ant-run plugin (http://wbarczynski.org/wp/wp-content/pom.xml_2.txt) to copy jars around but it can be done also using "pure" maven.
Skarab
+2  A: 

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>
Pascal Thivent
@Gilli Well, the `dependency:copy-dependencies` has a [`classifier`](http://maven.apache.org/plugins/maven-dependency-plugin/copy-dependencies-mojo.html#classifier) 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.
Pascal Thivent
@Pascal, is there a way to tell "copy-dependencies" to pretend classifier is not set even if it's set elsewhere in the POM?
Gili
@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).
Pascal Thivent
I ended up removing the use of a classifier in the POM. That fixed it. Thanks!
Gili
I 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)!
Martin
@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 the `outputDirectory`. But that's another story.
Pascal Thivent