0

The following is the directory structure of my java application:

application.jar
dependency-jars
     a.jar
     b.jar
     c.jar

The application executes fine when I use the following command: java -cp "application.jar;dependency-jars/*" com.my.Application. In addition to application dependencies, 'dependency-jars' folder will also have jars dropped by its consumers. I want to make it an executable jar so as to make it easy for its consumers to invoke it. For creating executable jar I am making use of maven jar plugin. I want to simulate the above command line. I used the following maven jar plugin configuration:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-jar-plugin</artifactId>
   <version>2.4</version>
   <configuration>
      <archive>
         <manifest>
            <mainClass>com.my.Application</mainClass>
            <addClasspath>true</addClasspath>
         </manifest>
         <manifestEntries>
            <Class-Path>dependency-jars/*</Class-Path>
         </manifestEntries>
      </archive>
   </configuration>
</plugin>

The generated jar when executed is not able to find its dependencies at run time. Is there anything wrong with the above.

Thanks.

Anand Patel
  • 6,031
  • 11
  • 48
  • 67
  • I have provided an answer using the maven-assembly-plugin. I have used this solution in the past and it should work for you too. Let me know in comments if you need more help. – Chandranshu Nov 16 '13 at 06:09

1 Answers1

0

You need to use the maven-assembly-plugin for this like:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-assembly-plugin</artifactId>
      <version>2.4</version>
      <configuration>
        <archive>
          <manifest>
            <mainClass>com.my.Application</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
      <executions>
        <execution>
          <id>make-assembly</id>
          <phase>package</phase> <!-- bind to the packaging phase -->
          <goals>
            <goal>single</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

and you run it with

mvn clean compile assembly:single

Compile goal should be added before assembly:single. Generally, this goal is tied to the build phase to execute automatically. This ensures the JAR is built when executing mvn install.

And this answer would not be complete without a mention of the maven-shade-plugin which can help you in case your dependency jars have conflicting package and class names.

Chandranshu
  • 3,669
  • 3
  • 20
  • 37
  • I am using maven dependency plugin to collect all dependencies of the application in 'dependency-jars' folder. I also want to allow any one to drop their jars in 'dependency-jars' folder once the application has been deployed. For supporting that, I am want to add 'dependency-jars' folder explicitly to the class path. The solution provided by you will not work in my case. – Anand Patel Nov 18 '13 at 04:34
  • Could you please elaborate a bit more on your use case? For example, what is the use of dropping a jar in the dependency-jars folder _after_ the application has been deployed? If the application depended on those jars, they should have been packages since the beginning. If new code has been added to the application which need those dependencies, then you need to rebuild and redeploy anyway. – Chandranshu Nov 18 '13 at 04:50
  • Also, I find that what you are doing is similar to how I'd have written an Ant build script. If I hazard a guess, is your use case that you have some dependencies which are not present in the maven repository (like proprietary JARs)? – Chandranshu Nov 18 '13 at 04:51
  • Let me briefly describe the use case related to consumer dropping a jar in the dependency-jars folder. My application is a spring based application. It is packaged with default behavior. However, consumer can change/override one or more aspects of it by providing different implementation to the application's published interfaces. For that, they have to drop their jar in the folder and make appropriate changes to wiring of the objects in the spring context file. – Anand Patel Nov 18 '13 at 05:05
  • hmm, that sounds like a perfectly valid use case. It looks like you are creating a container just the way Tomcat is a servlet container. You should update the question with this use case. I'm sure someone has already done this and will provide a nice answer. – Chandranshu Nov 18 '13 at 05:09