Java Exception Handling

Java Exception Handling – NoClassDefFoundError

Today we continue our adventure through the Java Exception Handling series with a close look at the java.lang.NoClassDefFoundError. In most cases, a java.lang.NoClassDefFoundError is thrown when a class reference was available during compile time, but has since disappeared (for whatever reason) during execution.

In this article we’ll explore the java.lang.NoClassDefFoundError in more detail, looking at where it resides in the Java Exception Hierarchy, along with some simple example code and module distribution practices that might lead to java.lang.NoClassDefFoundErrors being thrown in day-to-day development. Let’s get on with the show!

The Technical Rundown

When Should You Use It?

Understanding what might cause a java.lang.NoClassDefFoundError requires an understanding that running a Java application typically hinges on two major steps:

  1. The application must be compiled, which forces Java to grab all relevant and referenced packages/modules from the specified classpath, before it can generate executable code.
  2. The application or target script is then executed, utilizing all previously-compiled packages to properly gain access to the required classes.

That’s a extremely simplified explanation, but the critical aspect is that Java cannot execute an application without first compiling all the relevant code.

To illustrate, here we’ve setup a basic project called ClassLoader that contains two independent classes that we’ll be using: io.airbrake.Main and io.airbrake.Book, which we’re going to include in our compilation and make use of in the code.

Because Java is so dependant on how directory and file structures are built (at least, without using a helper framework like Maven or Gradle), for this example it’ll be important to show how our project is configured. Here’s our basic file structure, where coded entries are files and plain entries are directories:

  • ClassLoader
  • Book
  • io
  • airbrake
  • Book.java
  • ClassLoader
  • io
  • airbrake
  • utility
  • Logging.java
  • Main.java

Normally we’d place classes with identical parent namespacing (e.g io.airbrake.Book and io.airbrake.Main) into the same directory, but it’s important for this example that we separate them.

Once we’ve compiled these classes we’ve created an out/production directory in our main ClassLoader project directory that contains our converted .class files (this won’t always be true, as it depends on how you configure/build your own Java applications, but the overall concept is the same for most scenarios). Thus, our compiled output directory structure looks like this:

  • ClassLoader
  • out
  • production
  • Book
  • io
  • airbrake
  • Book.class
  • ClassLoader
  • io
  • airbrake
  • utility
  • Logging.class
  • Main.class

Many developers will probably use an IDE like IntelliJ IDEA or Eclipse when working with Java, which will (attempt) to automatically handle the classpath on your behalf, based on how you configure your project within the editor. For example, IntelliJ IDEA allows a developer to easily mark any directory as a "Source Root", which informs the editor that it should add that directory to the classpath list for the current project during compilation and execution.

For this reason, in most cases your development environment will do everything in its power to prevent you from accidentally getting in a situation where a java.lang.NoClassDefFoundError could be thrown. However, in some rare scenarios, particularly if you’re manually altering the classpath value, sometimes a java.lang.NoClassDefFoundError will pop up.

To illustrate this possibility, we’ll finally take a look at the basic code we’re using in this example:

In essence, all we’re doing in Main.main() is creating a new Book instance then attempting to output a basic info string to the console. Remember that, in this particular example, the compiled Main.class and Book.class files are located in slightly different output directories, so we’ll need to include both locations in our classpath value so things will run smoothly. Here we’re issuing the java console command and passing the -classpath parameter with both our ClassLoader and Book subdirectory locations as the two parent directories to be loaded. We’re then calling the io.airbrake.Main class, which will automatically run the Main.main() method for us:

As we can see, the result is what we expected: a new Book was created and we output some basic information about it.

Now, watch what happens if we remove the reference to where our compiled Book class is located (ClassLoader/out/production/Book) in the -classpath parameter value:

Lo and behold, we’ve caused a java.lang.NoClassDefFoundError to be thrown, which we were also able to successfully catch and output using the Logging.log() method. Essentially, what’s happening here is that our source code is configured correctly, and therefore we were able to compile everything just fine, since the JVM was able to locate the necessary io.airbrake.Book.java class file that was referenced. However, because we neglected to reference the compiled version of that Book.java class (in this case, in the form of Book.class, but often in .jar form or otherwise), the JVM couldn’t locate Book during runtime, so a java.lang.NoClassDefFoundError is thrown.

The Airbrake-Java library provides real-time error monitoring and automatic exception reporting for all your Java-based projects. Tight integration with Airbrake’s state of the art web dashboard ensures that Airbrake-Java gives you round-the-clock status updates on your application’s health and error rates. Airbrake-Java easily integrates with all the latest Java frameworks and platforms like Spring, Maven, log4j, Struts, Kotlin, Grails, Groovy, and many more. Plus, Airbrake-Java allows you to easily customize exception parameters and gives you full, configurable filter capabilities so you only gather the errors that matter most.

Check out all the amazing features Airbrake-Java has to offer and see for yourself why so many of the world’s best engineering teams are using Airbrake to revolutionize their exception handling practices!