111
votes

I am using Maven in my standalone application, and I want to package all the dependencies in my JAR file inside a library folder, as mentioned in one of the answers here:

How can I create an executable JAR with dependencies using Maven?

I want my final JAR file to have a library folder that contains the dependencies as JAR files, not like what the maven-shade-plugin that puts the dependencies in the form of folders like the Maven hierarchy in the .m2 folder.

Well, actually the current configuration does what I want, but I am having a problem with loading the JAR files when running the application. I can't load the classes.

Here's my configuration:

<plugins>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>prepare-package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                    <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                    <overWriteReleases>false</overWriteReleases>
                    <overWriteSnapshots>false</overWriteSnapshots>
                    <overWriteIfNewer>true</overWriteIfNewer>
                </configuration>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>lib/</classpathPrefix>
                    <mainClass>com.myapp.MainClass</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>install</id>
                <phase>install</phase>
                <goals>
                    <goal>sources</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

</plugins>

The project runs fine from Eclipse, and the JAR files are put in the library folder inside my final JAR file as I want, but when running the final JAR file from the target folder I always get ClassNotFoundException:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: com.myapp.MainClass. Program will exit.

How can I fix this exception?

8
which command do you use to run the jar? probably you may prefer maven exec plugin?Andrey Borisov
Is the exception message out of date compared with the POM file? It seems the main class com.myapp.MainClass is being searched for, not com.tastycafe.MainClass.Duncan Jones
@Duncan Jones, copy paste problem, i edited the questionMahmoud Saleh
Note that if you want jars inside the jar, then the standard classloaders in Java cannot understand them.Thorbjørn Ravn Andersen
How to make it place the maven dependencies in a lib folder but outside the JAR?ed22

8 Answers

87
votes

The following is my solution. Test it if it works for you:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/classes/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <!-- <classpathPrefix>lib</classpathPrefix> -->
                <!-- <mainClass>test.org.Cliente</mainClass> -->
            </manifest>
            <manifestEntries>
                <Class-Path>lib/</Class-Path>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

The first plugin puts all dependencies in the target/classes/lib folder, and the second one includes the library folder in the final JAR file, and configures the Manifest.mf file.

But then you will need to add custom classloading code to load the JAR files.

Or, to avoid custom classloading, you can use "${project.build.directory}/lib, but in this case, you don't have dependencies inside the final JAR file, which defeats the purpose.

It's been two years since the question was asked. The problem of nested JAR files persists nevertheless. I hope it helps somebody.

32
votes

Updated:

<build> 
  <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
      <execution> 
        <phase>install</phase> 
          <goals> 
            <goal>copy-dependencies</goal> 
          </goals> 
          <configuration> 
             <outputDirectory>${project.build.directory}/lib</outputDirectory> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build> 
24
votes

The simplest and the most efficient way is to use an uber plugin like this:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <finalName>uber-${project.artifactId}-${project.version}</finalName>
            </configuration>
        </plugin>

You will have de-normalized all in one JAR file.

12
votes

The executable packer maven plugin can be used for exactly that purpose: creating standalone java applications containing all dependencies as JAR files in a specific folder.

Just add the following to your pom.xml inside the <build><plugins> section (be sure to replace the value of mainClass accordingly):

<plugin>
    <groupId>de.ntcomputer</groupId>
    <artifactId>executable-packer-maven-plugin</artifactId>
    <version>1.0.1</version>
    <configuration>
        <mainClass>com.example.MyMainClass</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>pack-executable-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

The built JAR file is located at target/<YourProjectAndVersion>-pkg.jar after you run mvn package. All of its compile-time and runtime dependencies will be included in the lib/ folder inside the JAR file.

Disclaimer: I am the author of the plugin.

5
votes

following this link:

How To: Eclipse Maven install build jar with dependencies

i found out that this is not workable solution because the class loader doesn't load jars from within jars, so i think that i will unpack the dependencies inside the jar.

3
votes

Here´s how I do it:

    <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.project.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

And then I just run:

mvn assembly:assembly
2
votes

I found this answer to the question:

http://padcom13.blogspot.co.uk/2011/10/creating-standalone-applications-with.html

Not only do you get the dependent lib files in a lib folder, you also get a bin director with both a unix and a dos executable.

The executable ultimately calls java with a -cp argument that lists all of your dependent libs too.

The whole lot sits in an appasembly folder inside the target folder. Epic.

============= Yes I know this is an old thread, but it's still coming high on search results so I thought it might help someone like me.

1
votes

This is clearly a classpath problem. Take into consideration that the classpath must change a bit when you run your program outside the IDE. This is because the IDE loads the other JARs relative to the root folder of your project, while in the case of the final JAR this is usually not true.

What I like to do in these situations is build the JAR manually. It takes me at most 5 minutes and it always solves the problem. I do not suggest you do this. Find a way to use Maven, that's its purpose.