Why Am I Getting a Noclassdeffounderror in Java

Why am I getting a NoClassDefFoundError in Java?

This is caused when there is a class file that your code depends on and it is present at compile time but not found at runtime. Look for differences in your build time and runtime classpaths.

How can I solve java.lang.NoClassDefFoundError?

After you compile your code, you end up with .class files for each class in your program. These binary files are the bytecode that Java interprets to execute your program. The NoClassDefFoundError indicates that the classloader (in this case java.net.URLClassLoader), which is responsible for dynamically loading classes, cannot find the .class file for the class that you're trying to use.

Your code wouldn't compile if the required classes weren't present (unless classes are loaded with reflection), so usually this exception means that your classpath doesn't include the required classes. Remember that the classloader (specifically java.net.URLClassLoader) will look for classes in package a.b.c in folder a/b/c/ in each entry in your classpath. NoClassDefFoundError can also indicate that you're missing a transitive dependency of a .jar file that you've compiled against and you're trying to use.

For example, if you had a class com.example.Foo, after compiling you would have a class file Foo.class. Say for example your working directory is .../project/. That class file must be placed in .../project/com/example, and you would set your classpath to .../project/.

Side note: I would recommend taking advantage of the amazing tooling that exists for Java and JVM languages. Modern IDEs like Eclipse and IntelliJ IDEA and build management tools like Maven or Gradle will help you not have to worry about classpaths (as much) and focus on the code! That said, this link explains how to set the classpath when you execute on the command line.

Why am I getting a NoClassDefFoundError exception rather than a StackOverflow error?

This is not a bug and it also has nothing to do with static methods in interfaces.

The java.lang.instrument ASSERTION FAILED message is also not relevant and is just an artifact of running the code from IDE. Running the same class from the command line will result in Exception in thread "main" only.

Lets simplify your example to

public class Test {
public static void main( String[] args ) throws Exception {
recursive();
}

public static void recursive() throws Exception {
try {
Test.class
.getDeclaredMethod( "recursive" )
.invoke( null );
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}

What is going on:

  • The recursive method causes StackOverflowError, as expected.
  • The StackOverflowError is wrapped into InvocationTargetException which is thrown from the deepest nested call to method.invoke().
  • The InvocationTargetException is immediately caught and JVM tries to execute printStackTrace() but in order to do that it needs to load some classes. But remember that at this point the stack is depleted and any non-trivial methods will hit StackOverflowError again, which is exactly what happens somewhere inside the class loader when it tries to load some class required to print a stack trace. The class loader did found the class, but failed to load and initialize it, and it reports that as NoClassDefFoundError.

The following code will prove that InvocationTargetException indeed wraps StackOverflowError:

public class Test {
public static void main( String[] args ) throws Exception {
recursive();
}

public static void recursive() throws Exception {
try {
Test.class
.getDeclaredMethod( "recursive" )
.invoke( null );
} catch ( InvocationTargetException e ) {
System.out.println(e);
System.out.println(e.getTargetException());
}
}
}

And the following code will prove that if classes required to execute printStackTrace() are already loaded, then the code behaves as expected (prints a stack trace for InvocationTargetException caused by StackOverflowError:

public class Test {
public static void main( String[] args ) throws Exception {
new Exception().printStackTrace(); // initialize all required classes
recursive();
}

public static void recursive() throws Exception {
try {
Test.class
.getDeclaredMethod( "recursive" )
.invoke( null );
} catch ( InvocationTargetException e ) {
e.printStackTrace();
}
}
}

The open question is why reflection API handlesStackOverflowError at all, instead of simply terminating the whole call chain with the error.

ClassNotFoundException vs NoClassDefFoundError

NoClassDefFoundError

Thrown if the Java Virtual Machine or a ClassLoader instance tries to
load in the definition of a class (as part of a normal method call or
as part of creating a new instance using the new expression) and no
definition of the class could be found.

The searched-for class definition existed when the currently executing
class was compiled, but the definition can no longer be found.


ClassNotFoundException

Thrown when an application tries to load in a class through its string
name using: The forName method in class Class. The findSystemClass
method in class ClassLoader . The loadClass method in class
ClassLoader.


You have to understand that the JVM can't realize the definition of the class you deleted can't be found, as the class itself can't be found which automatically throw the ClassNotFoundException.

This exception happen at runtime so it does not matter if it compiled first or not, you deleted the file, therefore it can't be found and throw the exception.

Note that NoClassDefFoundError is not actually an exception, it is an Error derived from LinkageError while ClassNotFoundException derive directly from java.lang.Exception.

To resume, the NoClassDefFoundError globally simply mean that the JVM tried to access at runtime something that according to the compiled code should exists, but does not actually exist (or is not in the classpath).


Example to reproduce ClassNotFoundException

public class ClassNotFoundExceptionExample {

private static final String CLASS_TO_LOAD = "main.java.Utils";

public static void main(String[] args) {
try {
Class loadedClass = Class.forName(CLASS_TO_LOAD);
System.out.println("Class " + loadedClass + " found successfully!");
}
catch (ClassNotFoundException ex) {
System.err.println("A ClassNotFoundException was caught: " + ex.getMessage());
ex.printStackTrace();
}
}
}

Example to reproduce NoClassDefFoundError

Create a simple class Test

public class Test {
public Test() {
System.out.println("A new instance of the Test class was created!");
}
}

And a class NoClassDefFoundErrorExample

public class NoClassDefFoundErrorExample {
private static Test test = new Test();

public static void main(String[] args) {
System.out.println("The definition of Test was found!");
}
}

Now create a n executable .jar which execute the main method. You can specify it in the Manifest.txt file inside the .jar

Main-Class: NoClassDefFoundErrorExample

Now run the following commands

javac Test.java
javac NoClassDefFoundErrorExample.java
jar cfm NoClassDefFoundErrorExample.jar Manifest.txt NoClassDefFoundErrorExample.class
java -jar NoClassDefFoundErrorExample.jar

Notice the NoClassDefFoundError

Exception in thread "main" java.lang.NoClassDefFoundError: TestClass
at NoClassDefFoundErrorExample.(NoClassDefFoundErrorExample.java:2)
Caused by: java.lang.ClassNotFoundException: TestClass
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
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)
... 1 more

How do I resolve ClassNotFoundException?

Your classpath is broken (which is a very common problem in the Java world).

Depending on how you start your application, you need to revise the argument to -cp, your Class-Path entry in MANIFEST.MF or your disk layout.

Handle a NoClassDefFoundError?

I dont need to fix the missing classes because this is part of my program.

I am not completely sure what you are trying to achieve here but you should be able to catch a NoClassDefFoundError to prevent your JVM from crashing. Let A be a class that has-a reference to B. If B.class is not available at runtime, you can handle the NoClassDefFoundError as follows :

class C {
public static void main(String args[]) {
try {
A a = new A();
} catch (NoClassDefFoundError e) {
//log the error or take some action
}

System.out.println("All good here, lets continue");
}
}

What could cause a NoClassDefFoundError on one specific system only?

In my case, since I had set a timeout of 1,500 milliseconds on the future and because of the slower CPU clock speed of the misbehaving machine, the class was not fully initialised when the timeout occurred. Turns out, OkHttp is more or less the culprit, it takes more than 5 seconds to inistalise the client on the given machine.

All in all, I am no longer applying any timeout on the first try of the connection test to give OkHttp enough time to initialise itself.

Note that this would not solve the problem if the initialisation of the HTTPClient was to fail at a different point in the application lifecycle. But since the first try of the connection test is the first place to call into HTTPClient, this is the only place where it can be initialised.



Related Topics



Leave a reply



Submit