Find where java class is loaded from
Asked Answered
O

12

217

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?

Oster answered 22/10, 2008 at 20:44 Comment(0)
P
210

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
Pigtail answered 22/10, 2008 at 21:15 Comment(9)
To cut down on redundant typing, one can also use the shorter version: Test.class.getResource("Test.class"), which doesn't repeat the package name.Pantograph
What if the class is compiled, e.g. from a .groovy file?Pull
@meriton: Or, to survive refactorinsgs: Test.class.getResource(Test.class.getSimpleName() + ".class")Hostess
For BouncyCastleProvider full package name is required however.Limiting
It is possible for getClassLoader() to return null. See here for an extension to this method to handle that.Canonize
@Pantograph Class#getResource(String name) delegates to the object's class loader, i.e ClassLoader#getResource(String name) method.Fleta
Also the getResource can return null. This code won't work every time.Hag
@TomášZato: It will work if the class is available to the classloader. I agree that if the OP needs to cope with the possibility of the class not being available, then they'd need to do a null check - that's an easy modification though.Pigtail
I used this to load resources and this is where it failed. Specifically, it failed when I was running Maven test class - at that point, class in my project was trying to load resources from /target/test-classes instead of /target/classes. The problem was solved by using new MyClass().getClass().getResource("...") - or just this.getClass ... if in instantiated context.Hag
P
110

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

Prewar answered 23/10, 2008 at 7:16 Comment(2)
this worked very well, and doesn't have the problem of dealing with classes with null ClassLoaderAtrioventricular
@ries If one doesn't need to do this programmatically, this is definitely the way to go, and it did solve my problem. However, the OP had asked specifically how to do this programmatically.Millen
I
98
getClass().getProtectionDomain().getCodeSource().getLocation();
Idette answered 22/10, 2008 at 21:39 Comment(4)
Yup, although it doesn't work with a security manager installed and without the required permissions.Inlet
FYI, NPE = Null Pointer Exception. HTH!Pushy
This method is preferred as long as you have a reference to an instance, since you can load the same class from two different locations.Nautilus
Also doesn't work when called from a Java 9+ module (which of course you couldn't have known in 2008).Inordinate
A
29

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()

Aerography answered 22/10, 2008 at 21:53 Comment(0)
C
21

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";
}
Canonize answered 21/10, 2013 at 12:10 Comment(0)
M
5

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!

Mera answered 22/4, 2015 at 15:49 Comment(0)
B
3

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();
Backdrop answered 20/10, 2017 at 19:46 Comment(2)
Needs to be: URL classUrl = MyClass.class.getClassLoader().getResource("/" + className);Auberta
MyClass.class is important part - getClass() can return Proxy! Then you can get name like MyClass$$EnhancerBySpringCGLIB$$a98db882.class, and null URL.Misery
W
1

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 )

Wheat answered 22/10, 2008 at 20:49 Comment(0)
D
1

Simple way:

System.out.println(java.lang.String.class.getResource(String.class.getSimpleName()+".class"));

Out Example:

jar:file:/D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class

Or

String obj = "simple test"; System.out.println(obj.getClass().getResource(obj.getClass().getSimpleName()+".class"));

Out Example:

jar:file:/D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class

Deragon answered 7/2, 2020 at 20:27 Comment(0)
A
0

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
Athwart answered 14/2, 2017 at 23:48 Comment(0)
P
0

for unit test

If you need the location of a class called Coverage.java located in package com.acme.api

Class clazz = Coverage.class;
ClassLoader loader = clazz.getClassLoader();    
String coverageClazzCompiledAbsoluteTargetLocation = loader
.getResource(clazz.getCanonicalName().replace(".", File.separator) + ".class")
.getFile().replace(File.separatorChar + "$", "");
System.out.println(coverageClazzCompiledAbsoluteTargetLocation);

Result

/home/Joe/repositories/acme-api/target/test-classes/com/acme/api/Coverage.class

Note: Since java needs compilation, you cannot obtain the .java location (src/main/java/...). You need to compile .java into .class, so the location if you are using maven, will be inside of target folder

at runtime: JAR

If you build your app as jar, the location of class will be the jar location plus clazz package

at runtime: WAR

If you build your app as war, the location of class will be the war location (/bin folder in tomcat) plus clazz package

Papilloma answered 30/1, 2023 at 22:4 Comment(0)
O
-2

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.

Omland answered 22/10, 2008 at 20:46 Comment(2)
This returns the ClassLoader used for loading the class, isn't it? It does not find where the .class file is?Heartsome
No it doesn't. The classloader can actually reffer to completely different class path - means it will be totally unable to reah the actual class location.Hag

© 2022 - 2024 — McMap. All rights reserved.