1

I'm trying to build a Single Runnable jar containing my classes and dependencies, and after I managed to create the file, I became stuck. When I execute my jar:

java -jar Amp60-distribution.jar

I receive the following error message:

Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2521)
    at java.lang.Class.getMethod0(Class.java:2764)
    at java.lang.Class.getMethod(Class.java:1653)
    at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:494)
    at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:486)

Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 6 more

I verified my MANIFEST.MF and it does not contain the classpath:

Manifest-Version: 1.0
Built-By: jtormin
Build-Jdk: 1.7.0_45
Created-By: Apache Maven 3.0.4
Main-Class: gui/MainFrame
Archiver-Version: Plexus Archiver

My pom.xml:

    <build>
        <sourceDirectory>src</sourceDirectory>
        <resources>
            <resource>
                <directory>resources</directory>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                        <compress>true</compress>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <mainClass>gui/MainFrame</mainClass>
                            <classpathLayoutType>custom</classpathLayoutType>
                            <customClasspathLayout>
                                $${artifact.groupId}.$${artifact.artifactId}.$${artifact.extension}
                            </customClasspathLayout>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.4</version>
                <configuration>
                    <finalName>Amp60</finalName>
                    <outputDirectory>target</outputDirectory>
                    <descriptor>assembly/assembly.xml</descriptor>
                    <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>gui/MainFrame</mainClass>
                    </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>net.sf.opencsv</groupId>
            <artifactId>opencsv</artifactId>
            <version>2.3</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.1</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-math3</artifactId>
            <version>3.2</version>
        </dependency>
        <dependency>
            <groupId>org.jfree</groupId>
            <artifactId>jfreechart</artifactId>
            <version>1.0.15</version>
        </dependency>
        <dependency>
            <groupId>jakarta-regexp</groupId>
            <artifactId>jakarta-regexp</artifactId>
            <version>1.4</version>
        </dependency>
    </dependencies>
    <organization>
        <name>ISP</name>
    </organization>
</project>

The assembly.xml:

<assembly
    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.4">
    <id>distribution</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <directory>target/classes/</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>**</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>resources</directory>
            <outputDirectory>resources</outputDirectory>
            <includes>
                <include>**</include>
            </includes>
        </fileSet>
    </fileSets>
    <dependencySets>
        <dependencySet>
            <outputDirectory>/</outputDirectory>
            <useProjectArtifact>false</useProjectArtifact>
            <useTransitiveDependencies>true</useTransitiveDependencies>
        </dependencySet>
    </dependencySets>
</assembly>
jrtormin
  • 13
  • 1
  • 3
  • Does the accepted answer at http://stackoverflow.com/questions/1510071/maven-how-can-i-add-an-arbitrary-classpath-entry-to-a-jar help? – DaveH Nov 29 '13 at 18:06
  • Thanks, but it didn't work. I'm new to Maven, but I think that both situations are a little bit different. In this case Maven is not generating the Classpath. Even though, I tried the solution and eclipse reported the following problem: `Cannot find setter, adder nor field in org.apache.maven.archiver.ManifestConfiguration for 'manifestEntries'` – jrtormin Nov 29 '13 at 18:36

1 Answers1

3

I think there is couple of more elegant and simple ways to achieve your goal - build a JAR with all dependencies. At least extra file named assembly.xml confuses me. Try to remove your assembly.xml and maven-jar-plugin and use this:

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>gui.MainFrame</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> <!-- this is used for inheritance merges -->
      <phase>package</phase> <!-- bind to the packaging phase -->
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>

But in fact, I don't like maven-assembly-plugin because it extracts files from all JARs and packages all files to ONE jar. So there is possible problems with collisions - for example log4j.xml can be presented twice from 2 dependent JARs that was unpacked. So I suggest to use one-jar-plugin with dependency-plugin (remove maven-jar-plugin and maven-assembly-plugin with assembly.xml):

    <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.5.1</version>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>

                        <outputDirectory>${project.build.directory}/lib/</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.dstovall</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
            <executions>
                <execution>
                    <configuration>
                        <mainClass>gui.MainFrame</mainClass>
                        <attachToBuild>true</attachToBuild>
                    </configuration>
                    <goals>
                        <goal>one-jar</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Also you need to explicitly specify repository for one-jar-plugin:

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>
WelcomeTo
  • 811
  • 8
  • 11
  • Thank you, WelcomeTo. I used the second solution (onejar) and it worked. The only problem is that it could not load a resource and launched an exception: `Exception in thread "main" java.lang.reflect.InvocationTargetException Caused by: java.lang.NullPointerException at gui.MainFrame.main(MainFrame.java:145) ` This exception was caused by the following code line: `InputStream logFileConfiguration = ClassLoader.getSystemResourceAsStream("conf/log4j.properties");` The conf directory and log4j file are in jar, but I still didn't get why it could not find them. – jrtormin Nov 29 '13 at 21:24
  • @user1637370 Try replace your code by this: `Thread.currentThread().getContextClassLoader().getResourceAsStream("log4j.xml")`, or if it don't work, try this: `SomeYourClass.class.getClassLoader().getResourceAsStream("log4j.xml")` – WelcomeTo Nov 29 '13 at 22:25
  • It didn`t work, but I found the solution: `InputStream logFileConfiguration = MainFrame.class.getResourceAsStream("/conf/log4j.properties");` – jrtormin Dec 01 '13 at 16:20