Monday, May 17, 2010

ClassNotFoundException vs. NoClassDefFoundError

I have quite often seen people mistake a ClassNotFoundException for a NoClassDefFoundError and vice versa. So here is a break down on the differences.

java.lang.ClassNotFoundException: Class is not in the classpath, this could be due to there being 2 different active class loaders and each having different visibility, (this is often the case when working within application servers where you are not in control of the current class loaders), or just that the class is actually no there.

java.lang.NoClassDefFoundError: Is quite different, and generally means that the class is there but there was error reading the class definition. This quite often happens when an exception occurs in a static initializer block or static variable instantiation. The JVM throws a java.lang.ExceptionInInitializerError and the "unloads" the definition, any further attempts at accessing this class then result in a java.lang.NoClassDefFoundError.

While discussing it with a work colleague of mine he wrote the following code to illustrate the behaviour:

public class App {
  public static void main(String[] args) {
    try {
      App.class.getClassLoader().loadClass("NonExistent");
    } catch (Throwable e) {
      System.out.println(e.getClass().getName());
    }
    
    try {
      new BadStatic();
    } catch (Throwable e) {
      System.out.println(e.getClass().getName());
      System.out.println(e.getCause().getClass().getName());
    }
    
    try {
      new BadStatic();
    } catch (Throwable e) {
      System.out.println(e.getClass().getName());
    }
    
  }

}

package za.co.classNotFoundBadness;

public class BadStatic {

  static {
    if(true){
      throw new IllegalArgumentException("I am a bad static initialiser.");
    }
  }
  
  public BadStatic() {
    
  }
  
}

Output:
java.lang.ClassNotFoundException
First attempt:
java.lang.ExceptionInInitializerError
java.lang.IllegalArgumentException
Second attempt:
java.lang.NoClassDefFoundError

9 comments:

  1. Wow, this is quite wrong. ClassNotFoundException and NoClassDefFoundError mean the same error at different stages. ClassNotFoundException is a checked exception, so it can only be thrown where one is expected. However in Java every reference to a class from code is a potential class lookup, so when that class is not found the NoClassDefFoundError is thrown. In fact AFAICT NoClassDefFoundError will always be caused by a ClassNotFoundException from the class loader doing the loading/linking.

    ReplyDelete
    Replies
    1. No that's not true. They both appear same but underlying cause is different. see this link which clearly differentiate between NoClassDefFoundError and ClassNotFoundException

      Delete
  2. Could you code / show me an example? This is based on what I have found in my experience, and I have supplied a little bit of code to show that the behavior I described does actually occur. I'll gladly amend the post if proven otherwise, and quite happy to learn something new...

    ReplyDelete
  3. FWIW, I also seem to remember differences across platforms. Can't remember the details but on Linux i got a ClassNotFoundException and on Windows (for the same operation) it gave a NoClassDefFoundError.

    ReplyDelete
  4. I avoid Linux like the plague actually... yeah I know, not a very "open source" thing to say... But anyone reading this with a linux setup care to run the code in the post and see if there are any differences... ?

    I would think it very odd if there was... but stranger things have happened.

    More likely that you classpath and /or resources were different between the 2... leading to different errors for completely different reasons.

    ReplyDelete
  5. If you run: java -verbose NonExistent

    I think you can see an example of what Jevgeni described:

    Exception in thread "main" java.lang.NoClassDefFoundError: NonExistent
    Caused by: java.lang.ClassNotFoundException: NonExistent
    at java.net.URLClassLoader$1.run(URLClassLoader.java:202)

    ReplyDelete
  6. Thanks for that... We may be onto something here,
    lets look at the whole stacktrace:
    Exception in thread "main" java.lang.NoClassDefFoundError: NonExistent
    Caused by: java.lang.ClassNotFoundException: NonExistent
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    Could not find the main class: NonExistent. Program will exit.

    So the NoClassDefFoundError was caused by the ClassNotFoundException.
    Now to try figure out the details...

    There is "sun.misc.Launcher$AppClassLoader.loadClass" in the stacktrace,
    I went searching for the code and it is defined as a static:
    "static class AppClassLoader extends URLClassLoader "

    So isn't what is happening exactly what my blog entry said,
    the NoClassDefFoundError is caused by the JVM Unloading class because of an
    Exception in a static (in this case it just happens to be a ClassNotFoundException) ?

    Or am I missing something?

    ReplyDelete
  7. My test:

    class Test {
    public static void main (String... a) {
    try {
    System.out.println(Foo.Z);
    } catch (Throwable e) {
    e.printStackTrace();
    }
    System.gc();

    System.out.println("2nd");
    try {
    System.out.println(Foo.Z);
    } catch (Throwable e) {
    e.printStackTrace();
    }
    System.gc();

    System.out.println("3nd");
    System.out.println(new java.io.File("Foo.class").delete());
    try {
    System.out.println(Foo.Z);
    } catch (Throwable e) {
    e.printStackTrace();
    }
    }
    }


    class Foo {
    static {
    if (1==1) {throw new IllegalArgumentException("oops");}
    }
    public static String Z = "1";
    }

    1st: java Test
    java.lang.ExceptionInInitializerError
    at Test.main(Test.java:4)
    Caused by: java.lang.IllegalArgumentException: oops
    at Foo.(Foo.java:5)
    ... 1 more
    2nd
    java.lang.NoClassDefFoundError: Could not initialize class Foo
    at Test.main(Test.java:12)
    3nd
    true
    java.lang.NoClassDefFoundError: Could not initialize class Foo
    at Test.main(Test.java:21)


    2nd java Test (there is no Foo class)
    java.lang.NoClassDefFoundError: Foo
    at Test.main(Test.java:4)
    Caused by: java.lang.ClassNotFoundException: Foo
    at java.net.URLClassLoader$1.run(Unknown Source)

    2nd
    java.lang.NoClassDefFoundError: Foo
    at Test.main(Test.java:12)
    3nd
    false
    java.lang.NoClassDefFoundError: Foo
    at Test.main(Test.java:21)

    So NoClassDefFoundError is more generic error.
    Also ClassLoader caches classnames, so following calls will throw NoClassDefFoundError

    ReplyDelete
  8. CNFE is thrown when the requested class could not be found, while NCDE is thrown when a dependency of the requested class could not be found etc.

    ReplyDelete

Popular Posts

Followers