Find where java class is loaded from
-
03-07-2019 - |
Question
Does anyone know how to programmaticly find out where the java classloader actually loads the class from?
I often work on large projects where the classpath gets very long and manual searching is not really an option. I recently had a problem where the classloader was loading an incorrect version of a class because it was on the classpath in two different places.
So how can I get the classloader to tell me where on disk the actual class file is coming from?
Edit: What about if the classloader actually fails to load the class due to a version mismatch (or something else), is there anyway we could find out what file its trying to read before it reads it?
Solution
Here's an example:
package foo;
public class Test
{
public static void main(String[] args)
{
ClassLoader loader = Test.class.getClassLoader();
System.out.println(loader.getResource("foo/Test.class"));
}
}
This printed out:
file:/C:/Users/Jon/Test/foo/Test.class
OTHER TIPS
Another way to find out where a class is loaded from (without manipulating the source) is to start the Java VM with the option: -verbose:class
getClass().getProtectionDomain().getCodeSource().getLocation();
This is what we use:
public static String getClassResource(Class<?> klass) {
return klass.getClassLoader().getResource(
klass.getName().replace('.', '/') + ".class").toString();
}
This will work depending on the ClassLoader implementation:
getClass().getProtectionDomain().getCodeSource().getLocation()
Jon's version fails when the object's ClassLoader
is registered as null
which seems to imply that it was loaded by the Boot ClassLoader
.
This method deals with that issue:
public static String whereFrom(Object o) {
if ( o == null ) {
return null;
}
Class<?> c = o.getClass();
ClassLoader loader = c.getClassLoader();
if ( loader == null ) {
// Try the bootstrap classloader - obtained from the ultimate parent of the System Class Loader.
loader = ClassLoader.getSystemClassLoader();
while ( loader != null && loader.getParent() != null ) {
loader = loader.getParent();
}
}
if (loader != null) {
String name = c.getCanonicalName();
URL resource = loader.getResource(name.replace(".", "/") + ".class");
if ( resource != null ) {
return resource.toString();
}
}
return "Unknown";
}
Edit just 1st line: Main
.class
Class<?> c = Main.class;
String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", "");
System.out.println(path);
Output:
/C:/Users/Test/bin/
Maybe bad style but works fine!
Take a look at this similar question. Tool to discover same class..
I think the most relevant obstacle is if you have a custom classloader ( loading from a db or ldap )
Typically, we don't what to use hardcoding. We can get className first, and then use ClassLoader to get the class URL.
String className = MyClass.class.getName().replace(".", "/")+".class";
URL classUrl = MyClass.class.getClassLoader().getResource(className);
String fullPath = classUrl==null ? null : classUrl.getPath();
This approach works for both files and jars:
Class clazz = Class.forName(nameOfClassYouWant);
URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish
Assuming that you're working with a class named MyClass
, the following should work:
MyClass.class.getClassLoader();
Whether or not you can get the on-disk location of the .class file is dependent on the classloader itself. For example, if you're using something like BCEL, a certain class may not even have an on-disk representation.