Recently, after part of my hard drive crashed and I restored my Java development environment, I had trouble debugging one of my projects. This particular project was large, spread across multiple JAR files, and everything compiled just fine. However, when I went to run or debug it within my IDE, I consistently got a java.lang.NoSuchField Exception for a class member variable that was certainly there. When I ran the code from the command line via a script, it ran fine. I was perplexed.
A glance at the Oracle Java documentation reveals that this exception is thrown if an application tries to access or modify a field of an object that is no longer part of that object. As the documentation explains, this is something that’s normally caught by the compiler, but can occur if the class has become incompatible in some way. It might sound cryptic, and you may also wonder how this could occur. If the class compiles fine, then why would the object become incompatible? The answer lies in a dependency tree.
For example, let’s say you have Library A, which depends on Library B and Library C. But, Library B also depends on Library C (see Figure 1).
Figure 1 – Dependency trees like this are normal, but can cause issues if a dependency gets out of date.
Although I’ve labeled and referred to each as a “Library,” they can be .jar files, IDE projects, or Java Class files—It doesn’t matter, because it’s the dependency tree that’s the issue. This is normally not a big deal, but dependency trees like this can cause versioning issues, as was the case here.
Verbose Java Class Loading
The error derived from the fact that although Library A and Library C were updated, Library B was errantly referring to an older revision of Library C (one that indeed didn’t have the field being reported as missing) in an obscure location. Part of the issue was due to an out-of-sync Maven repository that threw my IDE off. To help uncover this, I added the following parameter to the Java command-line in the IDE’s run configuration:
The result is a verbose list of each class that’s loaded, and the class or .jar it’s loaded from with full path, such as:
[Loaded com.allure.JetStream.JetStream$JetStreamQueueScheduler from file:/Users/ericjbruno/dev/JetStream/dist/JetStream.jar]
There’s a ton of output (this is only one line as an example), but all you need to do is redirect it to a file and search for the offending class or field name. You’ll likely see multiple places where it’s getting loaded from, and one of them will assuredly be an out-of-date library (a class or .jar file). In my case, this was exactly what happened. I simply cleaned up the project paths, removed the older version of the offending JAR file, rebuilt, and I’ve been fine since.