I'm annoyed

Discussion in 'Java' started by Mike Schilling, Jul 31, 2008.

  1. 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.
     
    Mike Schilling, Jul 31, 2008
    #1
    1. Advertising

  2. Lew wrote:
    > Mike Schilling wrote:
    >> 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.

    >
    > 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.
     
    Mike Schilling, Jul 31, 2008
    #2
    1. Advertising

  3. Lew wrote:
    > Oops - sorry about the null post.
    >
    > Lew wrote:
    >>> NoClassDefFoundError is the standard response by the JVM when the
    >>> desired class, in this case AaaBbb, is not present at run time.

    >
    > Mike Schilling wrote:
    >> 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"
     
    Mike Schilling, Jul 31, 2008
    #3
  4. Mike Schilling

    Lew Guest

    Lew wrote:
    > > 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.


    "Mike Schilling" wrote:
    > 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.

    --
    Lew
     
    Lew, Jul 31, 2008
    #4
  5. Lew wrote:
    > Lew wrote:
    >>> 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.

    >
    > "Mike Schilling" wrote:
    >> 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.


    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.
     
    Mike Schilling, Jul 31, 2008
    #5
  6. Lew <> wrote:
    > "Mike Schilling" wrote:
    >> 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.


    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...
     
    Andreas Leitgeb, Jul 31, 2008
    #6
  7. Mike Schilling

    Lew Guest

    "Mike Schilling" wrote:
    > >> 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"


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


    "Mike Schilling" wrote:
    > 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.

    --
    Lew
     
    Lew, Jul 31, 2008
    #7
  8. Mike Schilling

    Mark Space Guest

    Mike Schilling wrote:

    > 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...
     
    Mark Space, Aug 1, 2008
    #8
  9. Mike Schilling wrote:
    > 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
     
    Abhijat Vatsyayan, Aug 1, 2008
    #9
  10. Mike Schilling

    EJP Guest

    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.
     
    EJP, Aug 1, 2008
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sky Sigal
    Replies:
    3
    Views:
    1,680
    John Saunders
    Jul 16, 2004
  2. sb
    Replies:
    10
    Views:
    4,634
    Andre Heinen
    Feb 25, 2004
Loading...

Share This Page