Too many times I watched the logs trying to understand why I got the NoSuchMethodError. I sometimes get it with other derivatives of IncompatibleClassChangeError (
AbstractMethodError, IllegalAccessError, InstantiationError, NoSuchFieldError) but
NoSuchMethodError is the most common one.
The reason for this error is simple – the class you want to use is not the one being loaded at run time. This can be another version of the third party that finds its way to the classpath, or some old copy of your class. The problem is usually pin-pointing where it got from.
For that I have a simple solution – which unfortunately requires some code modification.
All you need to do is add these lines to your code (modify slightly) and you will get the result:
String className = classYouWantToFind.getName(); String classFileRelativePath = className.replace('.', '/') + ".class"; java.net.URL classFileUrl = this.getClass().getClassLoader().getResource(classFileRelativePath); System.out.println(className + " comes from [" + classFileUrl.toString() + "]");
This code asks the
ClassLoader of the currently running object to find the .class representing the class you are looking for. Since the class loader searches for resources in the same order as it does for classes – it should find the correct one.
You can see a live example of this code on IDE One.
Note: You can always get this result by adding the
-verbose:class VM argument – but this will get you verbose output of every class in the system.
Every so often I need to figure out which jar(s) contain a certain class so I can figure out why an application acts the way it does – either since a class is missing in some environment or since the wrong class was loaded into the classpath.
When that happens, I use the following script. I saw it once in a company I worked at, and then again in another company.
I modified it slightly, but the credits do not go to me, they go to the anonymous person who wrote the initial code.
The script is available for download on GitHub.
Or you can simply copy it from here:
#!/bin/tcsh -f if ( $#argv < 2 ) then printf "Scans all the JARs in the specified directory for classes matching the specified string\n" printf "Usage: $0 <dir> <class-name-pattern>\n" printf "Example: $0 . Exception\n" printf 'Example: '$0' $JAVA_HOME/lib "com\/sun\/.*action"\n' exit 1 endif set DIR = "$1" set CLASS = "$2" foreach J ( `find $DIR -name "*.jar"` ) printf "." set res=`jar tvf $J | grep "$CLASS" | sed 's/$/;/'` set outputsize = `echo $res|wc -c` if ( $outputsize > 1 ) then printf "\nMatch found in [$J]\n" printf "$res\n" | tr ';' '\n' endif end printf "\n"