17

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
J Smith
  • 2,375
  • 3
  • 18
  • 36
  • Something doesn't add up. Presumably, you are writing a custom class loader, please include any overriden methods you may have defined for it. – Perception Apr 02 '13 at 01:52
  • 1
    `defineClass` does not throw ClassNotFoundException. If you're getting that exception it's coming from somewhere else. – Hot Licks Apr 02 '13 at 01:54
  • 1
    @j-smith It is better if u can give a sscce to show the problem. There are quite some possibilities for the unmatched exception. For example, the "final" exception cause the app to exit may be thrown by some outer level, for which it catch your NoClassDefFoundError and rethrow with a ClassNotFoundException. It is better if you can inspect the "cause" of the exception, and the call stack in the exception. It give you idea on where the exception is actually originated. – Adrian Shum Apr 02 '13 at 01:54
  • @AdrianShum If you catch an `Exception ` and then get the stack trace of the exception, that is a perfectly viable solution. – syb0rg Apr 02 '13 at 02:00
  • @syb0rg For debugging, otherwise you're not actually solving anything. – Sotirios Delimanolis Apr 02 '13 at 02:02
  • do you really have `package` as a package name? – ZhongYu Apr 02 '13 at 02:47
  • @zhong.j.yu - Yeah, my guess is that there is something amiss with the naming. And I suspect the above ex trace has been "sanitized", so we can't tell if there are some subtleties in the naming that are mucking things up. – Hot Licks Apr 02 '13 at 03:08
  • JSmith -- In real life, are the two class names in the exception message identical (other than . <=> /) as you have shown, or are they somehow different? – Hot Licks Apr 02 '13 at 03:13
  • (Hint: The class you're trying to load -- put it into a .class file and see if you can load it "normally". Presumably the reason for your error will become obvious.) – Hot Licks Apr 02 '13 at 11:43

5 Answers5

12

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.

tbodt
  • 16,609
  • 6
  • 58
  • 83
Perception
  • 79,279
  • 19
  • 185
  • 195
  • 1
    The fact that the code is generating a NoClassDefFoundError with an underlying cause of ClassNotFoundException does not answer the question. I also confirmed that this unusual behavior persists even with a conventional package name. – J Smith Apr 02 '13 at 15:02
  • @JSmith - please post your code that shows a ClassNotFoundException being thrown from a `defineClass` method being called, yet not allowing an explicit catch block. – Perception Apr 02 '13 at 15:07
  • @JSmith Perception's answer answers the question very well: The "underlying cause" `ClassNotFoundException` is wrapped by the `NoClassDefFoundError` and therefore wont be caught by `catch(ClassNotFoundException e)`. – Volker Seibt Sep 13 '13 at 10:09
7

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.

Hot Licks
  • 47,103
  • 17
  • 93
  • 151
2

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.

brianestey
  • 8,202
  • 5
  • 33
  • 48
0
//and yet this works just fine...
try
{
    throw new Error(new IOException());
}
catch (Error e)
{
    System.out.println("err");
}

Replace it with:

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

Try a e.printStackTrace() and you'll see a similar output.

Hardcoded
  • 6,476
  • 2
  • 22
  • 20
-1

As has been pointed out already, Java won't allow you to handle errors.

Anyway, I'm not really sure what your reasons are for trying to work around these exceptions (and errors) but these are occurrences that programmers don't really need to worry about (most of the time). To me this is a symptom that there is a problem elsewhere in your code/project. If the system throws a ClassNotFoundException, and it allows you to catch it, how would you handle it? Or would you rather address the actual problem that a certain class required by your application is not in the classpath?

Also, you may want to check the difference between NoClassDefFoundError and ClassNotFoundException to better address your problem.

Community
  • 1
  • 1
Psycho Punch
  • 6,418
  • 9
  • 53
  • 86
  • 1
    Yes, you definitely can "handle" errors, from the purely mechanical standpoint of catching them. In general, though, you may not be able to cleanly *recover* from them. – Hot Licks Apr 02 '13 at 02:42
  • 1
    @JSmith - In general, reasonable applications wouldn't handle **errors** as well as **unchecked exceptions**. Rather, they would enforce such conditions/mechanisms as they would prevent such errors or exceptions from being thrown, hence, there is no question of handling them. I would say they should be prevented (by the application developers) before they're thrown. – Lion Apr 02 '13 at 02:57
  • Yeah, I shouldn't have said 'Java won't allow' as if it's going to complain about it because try-catch-finally was designed around `Throwable`s and not just `Exception`s. It's more of you can but you should not. – Psycho Punch Apr 02 '13 at 03:20