Search code examples
javaclasspathnoclassdeffounderrorclassnotfoundexception

Java NoClassDefFoundError even though the class exists


I'm trying to figure out how class importing works in Java. I have the following file structure:

testProject
    pkgA
        A.java
        A.class
    dir
        pkgB
            B.java
            B.class

The contents of A.java are:

package pkgA;

public class A {
    public static String funcA() {
        return "funcA in class A in pkgA";
    }
}

The contents of B.java are:

package pkgB;

import pkgA.A;

public class B {
    public static void main(String[] args) {
        System.out.println((new A()).funcA());
    }
}

In testProject I run:

javac pkgA/A.java

The above command doesn't print anything.

In testProject/dir I run:

javac pkgB/B.java -classpath ..

The above command doesn't print anything.

In testProject/dir I run:

java pkgB/B -classpath ..

The above command prints the following:

Exception in thread "main" java.lang.NoClassDefFoundError: pkgA/A
    at pkgB.B.main(B.java:7)
Caused by: java.lang.ClassNotFoundException: pkgA.A
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
    ... 1 more

What am I doing wrong?

Giving the classpath as an absolute path doesn't help.

$ java -version
java version "1.7.0_51"
OpenJDK Runtime Environment (IcedTea 2.4.4) (7u51-2.4.4-0ubuntu0.12.04.2)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)

OS is Ubuntu 12.04

Thanks!


Solution

  • Note that your classpath spec must preceed classes or .java files e.g.

    java -classpath .. pkgB/B 
    

    (the same applies to the javac invocation).

    I would compile everything at the same time e.g.

    javac -classpath {whatever} {complete list of .java files}
    

    for consistency's sake.

    Specify the compiler output directory to be separate to your source (e.g. a directory called classes). That makes life simpler in terms of managing your code and the compiled artifacts.

    Going forward, you should investigate a build tool such as Maven or Ant (or Gradle or Sbt etc.). That will make life much more manageable as you add source files, config or dependencies.