I'm annoyed

M

Mike Schilling

I have some Java code that analyzes Java code using reflection. It
loads classes using ClassLoader.loadClass() (catching the
ClassNotFoundException if they're missing) and then uses reflection to
gather data about them. I started up what should have been a long run
before I left work, and later this evening remoted in to find that it
had died almost immediately.

Why? It appears that trying to load class AaaBbb but finding class
Aaabbb whose name differs only in case (quite easy to do on a
case-insensitive file system), instead of throwing a
ClassNotFoundException, throws a NoClassDefFoundError (that's right,
Error.) This was not caught, and caused the program to exit. This is
not documented behavior. It's not hard to fix (catch Throwable
instead of the expected ClassNotFoundException), but the result is
that something which should have completd overnight might or might not
be done by tomorrow morning.
 
M

Mike Schilling

Lew said:
NoClassDefFoundError is the standard response by the JVM when the
desired class, in this case AaaBbb, is not present at run time.

As documented, it's when a class referenced via normal Java processing
(e.g. running "new" on it) can't be found at run time. Here my code
was explicitly calling Classloader.loadClass();
The problem is that the reflective code didn't catch that the class
was missing. So it passed on to the JVM the request to go ahead and
load the class. That's why it was an Error, not an Exception. It's
an Error when the situation is so tangled that the JVM cannot fix
it.

It's not really tangled. The Classloader opens the file and find that
it contains the wrong class; really not much more complex than not
being able to open the file.
Thus you experienced the correct behavior.

In this case I infer that you were running under Windows, and the OS
lied to the JVM about the availability of the class, precluding the
Exception and forcing the Error.

I'm sure that the implementation is something like that. Still, it
wouldn't have been hard for loadClass() to catch the Error and throw
an Exception; that's the fix I put in. And it would result in the
bloody method behaving as documented.
 
M

Mike Schilling

Lew said:
Oops - sorry about the null post.

Mike said:
As documented, it's when a class referenced via normal Java
processing (e.g. running "new" on it) can't be found at run time.
Here my code was explicitly calling Classloader.loadClass(); ...
I'm sure that the implementation is something like that. Still, it
wouldn't have been hard for loadClass() to catch the Error and
throw
an Exception; that's the fix I put in. And it would result in the
bloody method behaving as documented.

The documentation says that NoClassDefFoundError is "[t]hrown 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."
You performed a normal method call, 'loadClass()'. My analysis was
that the error occurred on the attempt to load the class, completely
consistent with the documentation that it occurs when the JVM or
"ClassLoader instance tries to load in the definition". This
happened at run time. The action was entirely consistent with the
documentation.

Excpet that it didn't happen "as part of a normal method call or as
part of creating a new instance using the new expression"
 
L

Lew

Mike Schilling said:
Excpet that it didn't happen "as part of a normal method call or as
part of creating a new instance using the new expression"

Except that it did happen as part of a normal method call.
 
M

Mike Schilling

Lew said:
Except that it did happen as part of a normal method call.

What in Java does not? I read "as part of a normal method call" as
"the class in loaded as a side effect of calling a method". This
wasn't a side effect, it was the purpose of the call.
 
A

Andreas Leitgeb

Lew said:
Except that it did happen as part of a normal method call.

The only method call, that could itself (not the method, but the call)
cause a class to be loaded, (and that furthermore I can currently think
of) would be a static method on a class that wasn't yet loaded before,
but a static method call isn't a "normal method call" in my own
dictionary.

Then there's of course also the trivial possibility of a
method (of an already loaded class) like loadClass()
explicitly throwing that exception ... that should rather
be referred to as "as part of a normal throws-clause",
not "as part of a normal method call".

Just trying to put my finger on what appears to me the root
confusion...
 
L

Lew

Mike Schilling said:
What in Java does not?  

Constructor calls.
I read "as part of a normal method call" as
"the class in loaded as a side effect of calling a method".  This
wasn't a side effect, it was the purpose of the call.

There is no mention of "side effect" behavior in the Javadocs, so you
are pulling that rabbit out of a hat.

I read "as part of a normal method call" as distinct from the next
clause in the very same sentence, "or as part of creating a new
instance using the new expression". It is clear, since there is not a
Java concept of "normal method call" otherwise, that they meant normal
method vs. new constructor call. This is consistent with the sentence
structure, which clearly contrasts the "normal method call" clause
from the "new expression" clause.

There is no "normal vs. abnormal" method call distinction in Java, so
that cannot be relevant to what they meant.
 
M

Mark Space

Mike said:
I'm sure that the implementation is something like that. Still, it
wouldn't have been hard for loadClass() to catch the Error and throw
an Exception; that's the fix I put in. And it would result in the
bloody method behaving as documented.


I agree with you, it feels counterintuitive to throw an error that is so
closely related to a documented exception.

OTOH... "this is why we test." I know that may sound flippant, but Sun
has bugs too. You may have found one, or something that is close enough
to be fairly labeled an undesirable feature. Sun (or any other API
vendor) isn't always going to get it 100% correct, so we all have to
test. Obviously, your tests were missing a couple of vital cases. Live
and learn...
 
A

Abhijat Vatsyayan

Mike said:
I have some Java code that analyzes Java code using reflection. It
loads classes using ClassLoader.loadClass() (catching the
ClassNotFoundException if they're missing) and then uses reflection to
gather data about them. I started up what should have been a long run
before I left work, and later this evening remoted in to find that it
had died almost immediately.

Why? It appears that trying to load class AaaBbb but finding class
Aaabbb whose name differs only in case (quite easy to do on a
case-insensitive file system), instead of throwing a
ClassNotFoundException, throws a NoClassDefFoundError (that's right,
Error.) This was not caught, and caused the program to exit. This is
not documented behavior. It's not hard to fix (catch Throwable
instead of the expected ClassNotFoundException), but the result is
that something which should have completd overnight might or might not
be done by tomorrow morning.
Heres what Java language specification says about Errors (I am kind of
ambiguous about this; it makes sense most of the times but not always):

Those unchecked exception classes which are the error classes (Error and
its subclasses) are exempted from compile-time checking because they can
occur at many points in the program and recovery from them is difficult
or impossible. *A program declaring such exceptions would be cluttered,
pointlessly.*

Abhijat
 
E

EJP

Lew wrote:> It is weird that it failed to realize that it couldn't find
the class
when it was trying to find it at first, and only fails at a later phase,
but that is explainable by the refusal of Windows to honor case
distinction in file names.

You can consider there to be two phases:

(a) find a .class file of the correct name on the CLASSPATH: failure
here causes a ClassNotFoundException

(b) load the contents of that file as a Class; the file must contain the
definition of a class whose name and package matches the file: failure
here causes NoClassDefFoundError.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top