Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

If a NoClassDefFoundError is caused by a ClassNotFoundException, why does Java expect you to catch both throwables?

When I run this code the app exits with a ClassNotFoundException:

//uncaught ClassNotFoundException
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (NoClassDefFoundError e)
{
}

When I attempt to compile this code, the compiler complains that the ClassNotFoundException is not reachable because it is not thrown from within the try-clause of the try-catch statement.

//Won't compile
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (ClassNotFoundException e)
{
}

When I run this code, the only throwable that is caught is a NoClassDefFoundError.

//catches throwable of type java.lang.NoClassDefFoundError,
//with a java.lang.ClassNotFoundException as its cause
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
}
catch (Throwable e)
{
    System.out.println(e.getClass().getName());
    System.out.println(e.getCause().getClass().getName());
}

The following code will compile and catch the error (and only the error), but it's clumsy:

//possible workaround
try
{
    Class<?> clazz = defineClass(null, bytes, 0, bytes.length, null);
    table.put(clazz.getName(), clazz);
    if (1 == 0) throw new ClassNotFoundException(); // we want the code to compile
}
catch (ClassNotFoundException e)
{
    System.out.println("ex");
}
catch (NoClassDefFoundError e)
{
    System.out.println("err");
}

And yet when I write the following, I can get away without a catch clause for the cause of the error:

//and yet this works just fine...
try
{
    throw new Error(new IOException());
}
catch (Error e)
{
    System.out.println("err");
}

Example 3 would lead me to conclude that the throwable was a NoClassDefFoundError. Example 1 would lead me to conclude that the throwable was a ClassNotFoundException. And yet, Example 2 shows that java won't even let me write code to properly catch the ClassNotFoundException.

Just when I was about to conclude that the problem here is the error-caused-by-an-exception, I ran the code shown in the previous example which shows that that is not the rule.

Can someone please explain what's going on here?

PS: this is the stack trace:

 java.lang.NoClassDefFoundError: com/my/pckage/MyClass
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
at Main$MyClassLoader.getClasses(Main.java:78)
at Main.main(Main.java:109)
 Caused by: java.lang.ClassNotFoundException: com.my.pckage.MyClass
at java.lang.ClassLoader.findClass(ClassLoader.java:522)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
... 4 more
like image 868
J Smith Avatar asked Apr 02 '13 01:04

J Smith


People also ask

What is difference between NoClassDefFoundError and ClassNotFoundException in Java?

Both ClassNotFoundException and NoClassDefFoundError are the errors when JVM or ClassLoader not able to find appropriate class while loading at run-time. ClassNotFoundException is a checked exception and NoClassDefFoundError is an Error which comes under unchecked.

Can we catch NoClassDefFoundError in Java?

In the case of NoClassDefFoundError, the class was present at compile time, but Java runtime could not find it in Java classpath during runtime.

Can we catch ClassNotFoundException in Java?

ClassNotFoundException is a checked exception, so it has to be catch or thrown to the caller. ClassNotFoundException always occurs at runtime because we are indirectly loading the class using Classloader. Java compiler has no way to know if the class will be present in the classpath at runtime or not.

How do I fix Java Lang NoClassDefFoundError error?

lang. NoClassDefFoundError, which means the Class Loader file responsible for dynamically loading classes can not find the . class file. So to remove this error, you should set your classpath to the location where your Class Loader is present.


3 Answers

So, you are misunderstanding your stack trace.

java.lang.NoClassDefFoundError: com/my/package/MyClass
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:791)
    at Main$MyClassLoader.getClasses(Main.java:78)
    at Main.main(Main.java:109)
Caused by: java.lang.ClassNotFoundException: com.my.package.MyClass

Your code is generating a NoClassDefFoundError. The underlying cause is a ClassNotFoundException. Remember that cause is a property of the Throwable class, and that when printing stacktraces, Java will display information both on the direct exception and its underlying cause(s). It's tougher to say why the define method is failing internally, but one thing is for sure - you cannot use the keyword package in a package name.

like image 62
Perception Avatar answered Oct 13 '22 20:10

Perception


NoClassDefFoundError occurs when the .class for a class is found, but the class cannot be constructed from that .class.

There are several different scenarios that occur commonly, plus a few more obscure ones.

  • The .class file contains a name (and package) that does not match the class file name/package
  • A class that was needed to verify and initialize the class could not be found
  • An error occurred during class initialization

In most of these scenarios there is another error or exception that occurs earlier, is caught by the class loader, and the new error is signaled.

It's not clear exactly which scenario is occurring in the above exception traceback, but I'm guessing some sort of name mismatch.

like image 41
Hot Licks Avatar answered Oct 13 '22 19:10

Hot Licks


NoClassDefFoundError is actually a subclass of Error and these should not be caught. See the docs of Error for details. The important note below:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch. Most such errors are abnormal conditions.

A method is not required to declare in its throws clause any subclasses of Error that might be thrown during the execution of the method but not caught, since these errors are abnormal conditions that should never occur.

For this reason, I think you should take a closer look at your code to see what you are doing wrong.

like image 41
brianestey Avatar answered Oct 13 '22 20:10

brianestey