ClassNotFoundException despite the manifest classpath including a .jar which contains the class

I have a maven java project that I am trying to run from the command line. The project is built using Netbeans 8.1. It is built to java-snap-2.0.jar with the maven-dependency-plugin and maven-jar-plugin.

In my root/target directory, I find a lib/ directory containing all the .jar needed for my project's dependencies. I have, for instance, a snap-core-6.0.0-SNAPSHOT.jar which contains, among others, org/esa/snap/core/datamodel/Product.class . In my executable jar, I have a META-INF/MANIFEST.MF file which contains a list of white-space-seperated paths to the jar files in the lib/ directory, including lib/snap-core-6.0.0-20170810.175327-200.jar.

Despite this, when I run the jar file from the command line like so : java -jar java-snap-2.0.jar argument1, argument2 ... argumentN, I get the following error :

Exception in thread "main" java.lang.NoClassDefFoundError: org/esa/snap/core/datamodel/Product
    at com.batchprocessing.java.snap.ProcessMultiTemporal.main(ProcessMultiTemporal.java:56)
    at com.batchprocessing.java.snap.Main.ProcessMultiTemporalHPC(Main.java:178)
    at com.batchprocessing.java.snap.Main.main(Main.java:189)
Caused by: java.lang.ClassNotFoundException: org.esa.snap.core.datamodel.Product
    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)
    ... 3 more

Here is an excerpt from the pom.xml file :

(...)    
<build>
    <plugins>
        <!-- Copy dependencies during package phase to root/lib directory -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <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>
        <!-- Build an executable JAR and add classpaths (in lib/) to manifest -->
        <plugin>             
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>com.batchprocessing.java.snap.Main</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    (... other plugins ...)
</build>
(...)

I would greatly appreciate help figuring this out. I've been using this application for a year by running it from the IDE, but I'd like to be able to run it from the command line and move it to other machines (by moving the executable jar and the lib/ directory). I run into other issues if I try using a jar-with-dependencies or shade approach, so I'd like to get this setup (maven-jar-plugin + maven-dependency-plugin) working.

Upvotes: 1

Views: 1215

Answers (1)

Alright, the issue (as rightly identified by Roman Pushkovskiy) was that the names of the jar files in the manifest file were different from their names in the lib directory. These dependencies are mostly snapshots, and so the name of the jar is something like dependency-1.0.0-SNAPSHOT.jar. In the manifest, they would be attributed a unique name based on the date of the snapshot : lib/dependency-1.0.0-20170810.175327-200.jar. The solution was to add this line to the maven-jar-plugin : <useUniqueVersions>false</useUniqueVersions>.

Updated pom.xml excerpt :

(...)
    <build>
        <plugin>             
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>com.batchprocessing.java.snap.Main</mainClass>
                        <useUniqueVersions>false</useUniqueVersions>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        (... other plugins ...)
    </build>
(...)

Hope this can help others !

Upvotes: 4

Related Questions