Class in jar not found at runtime, but was used to compile

nook picture nook · Jul 10, 2013 · Viewed 13.7k times · Source

After I build this project from an ant file, I recieve a jar that contains all of the classes I built. When I try to run this jar, I get the following error:

Exception in thread "main" java.lang.NoClassDefFoundError: javax/media/j3d/SceneGraphObject

This error indicates that a one of the jars, specifically the j3dcore.jar from java3d, I am using can not be found. However, this jar is on the classpath when compiling through the ant build into the class files.

Why can this class not be found at runtime, but it is found at compile time? Do I have to manually change my classpath in my shell when running the jar as well as change it in the ant build?

If I add the jars to my classpath using java -cp j3d/*.jar -jar idv.jar

I get the error Error: Could not find or load main class j3d.j3dutils.jar

Answer

Jon Skeet picture Jon Skeet · Jul 10, 2013

Do I have to manually change my classpath in my shell when running the jar as well as change it in the ant build?

Yes, absolutely. Making a class available at compile-time doesn't embed the class into your output or anything like that. It just makes it available to the compiler (to find out what methods are present etc).

If I add the jars to my classpath using java -cp j3d/*.jar -jar idv.jar

Yes, it would - because that's being expanded into:

java -cp j3d/foo.jar j3d/bar.jar ... -jar idv.jar

It's not clear to me whether -cp is meant to work at all with -jar, given this documentation:

When you use this option, the JAR file is the source of all user classes, and other user class path settings are ignored.

One option is to set the classpath within the manifest of the jar file itself. For example:

Class-Path: j3d/foo.jar j3d/bar.jar

Another would be to ignore the -jar command-line option for now, and use:

java -cp j3d/*:idv.jar your.class.name.Here

Note the * rather than *.jar, as documented:

As a special convenience, a class path element containing a basename of * is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR (a java program cannot tell the difference between the two invocations).