views:

858

answers:

5

Hello!

I often encounter distributions of Java applications or libraries which use Maven as their build tool.

Some of them, sadly, don't provide standalone (or redistributable) jars.

Is it possible to build Maven-based applications in such a way, that the build result contains all dependencies and can be redistributed to work out-of-the box?

I tried to build Jackrabbit's OCM module. For some very "intelligent" reasons there is no downloadable standalone version.
So I built Jackrabbit with Maven (the source package of Jackrabbit includes OCM), and got the same jar as found in the apache repository. The jar doesn't contain necessary dependencies and is useless to me.

A: 

Change the pom.xml file and use the <Embed-Dependency> directive. A similar example can be found here so you can adapt it to your scenario.

<Embed-Dependency>*;scope=!test;inline=true</Embed-Dependency>

I think this should do the trick.


Here is the example at the above URL that seems to give timeout.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"&gt;
    <modelVersion>4.0.0</modelVersion>
    <groupId>br.gov.lexml</groupId>
    <artifactId>toolkit</artifactId>
    <packaging>bundle</packaging>
    <version>3.0</version>
    <parent>
     <artifactId>lexml</artifactId>
     <groupId>br.gov.lexml</groupId>
     <version>1.0</version>
    </parent>
    <build>
     <finalName>Lexml_Toolkit-2.0</finalName>
     <plugins>
      <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-compiler-plugin</artifactId>
       <configuration>
        <source>1.5</source>
        <target>1.5</target>
       </configuration>
      </plugin>
      <plugin>
       <groupId>org.apache.felix</groupId>
       <artifactId>maven-bundle-plugin</artifactId>
       <extensions>true</extensions>
       <configuration>
        <instructions>
         <!--_include>src/toolkit/resources/META-INF/MANIFEST.MF</_include-->

         <Export-Package>*;-split-package:=merge-last</Export-Package>
         <Bundle-Activator>br.gov.lexml.borda.Toolkit</Bundle-Activator>
         <Bundle-Name>Toolkit</Bundle-Name>
         <Private-Package />
         <Embed-Dependency>*;scope=!test;inline=true</Embed-Dependency>
         <Bundle-ClassPath>.,{maven-dependencies}</Bundle-ClassPath>
        </instructions>
       </configuration>
      </plugin>
     </plugins>
    </build>
    <dependencies>
     <dependency>
      <groupId>org.apache.xmlbeans</groupId>
      <artifactId>xmlbeans</artifactId>
      <version>2.4.0</version>
     </dependency>
     <dependency>
      <groupId>org.apache.xmlbeans</groupId>
      <artifactId>xmlbeans-xmlpublic</artifactId>
      <version>2.4.0</version>
     </dependency>
     <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.15</version>
     </dependency>
     <dependency>
      <groupId>br.gov.lexmlbeans</groupId>
      <artifactId>lexmlbeans</artifactId>
      <version>3.0</version>
     </dependency>
    </dependencies>
</project>
smink
Your link results in timeout. Please tell me where to put the directive. I can't find usable instructions on the web.
ivan_ivanovich_ivanoff
Just pasted the document comments inline in the answer. Hope that helps.
smink
Sorry, I'm totally new to maven, and, honestly, I don't even want to go deeper in it. So, I don't know: 1) Do I have to edit the main pom.xml, or that one of the desired module (which I want to build as a redist package), 2) The Bundle-Activator seems to be something related to your project, so how would I alter it to make it work? The main problem is: I'm doing everything remotely though SSH, so my flexibility of trying things around is very limited.
ivan_ivanovich_ivanoff
+1  A: 

You may have some luck with the appassembler plugin. Failing that, take a look at the assembly plugin. That's more flexible, but lower level. If you're using the assembly plugin, you may find the chapter on it in maven: the definitive guide to be useful.

Dominic Mitchell
A: 

I believe the Maven Shade Plugin will satisfy your needs. I use it when I am building command line interface tools to create an Uber JAR including my classes and along with the classes from all my dependencies.

Its very easy to use and I think this example is self-explanatory.

bmatthews68
+1  A: 

As Dominic said, using the assembly plugin will do the trick. You would usually configure it inside your own project's POM to gather and package all required dependencies:

  ...
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
    </configuration>
  </plugin>
  ...

jar-with-dependencies is predefined by the assembly plugin and will include all dependencies in the final package (see the documentation here).

If you don't want to use Maven for your own project, you will need to modify the libraries' POMs and repackage them yourself (download the sources, add the above snippet to pom.xml and run mvn package). Beware of duplicate or incompatible transitive dependencies if you use multiple libraries. exclusions might help in that case (see documentation here).

springify
A: 

As a couple of the posters said, the assembly plugin is a good way of creating a complete jar file, with all project dependencies. However, you don't actually have to modify the pom.xml file. Simply run:

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

... in order to create a jar file. If you want to do anything more advanced, you should probably modify pom.xml, and create a custom assembly descriptor.

oksrei