Encuentra dónde se carga la clase java

¿Alguien sabe cómo averiguar programáticamente dónde el cargador de clases java realmente carga la clase?

A menudo trabajo en proyectos grandes donde el classpath es muy largo y la búsqueda manual no es realmente una opción. Recientemente tuve un problema donde el cargador de clases estaba cargando una versión incorrecta de una clase porque estaba en el classpath en dos lugares diferentes.

Entonces, ¿cómo puedo hacer que el cargador de clases me diga de dónde viene el archivo de clase real?

Editar: ¿Y si el cargador de clases no carga la clase debido a una discrepancia en la versión (o algo más), de todos modos podríamos averiguar qué archivo está tratando de leer antes de leerlo?

Aquí hay un ejemplo:

package foo; public class Test { public static void main(String[] args) { ClassLoader loader = Test.class.getClassLoader(); System.out.println(loader.getResource("foo/Test.class")); } } 

Esto impreso:

 file:/C:/Users/Jon/Test/foo/Test.class 

Otra forma de averiguar dónde se carga una clase (sin manipular la fuente) es iniciar la máquina virtual Java con la opción: -verbose:class

 getClass().getProtectionDomain().getCodeSource().getLocation(); 

Esto es lo que usamos:

 public static String getClassResource(Class klass) { return klass.getClassLoader().getResource( klass.getName().replace('.', '/') + ".class").toString(); } 

Esto funcionará según la implementación de ClassLoader: getClass().getProtectionDomain().getCodeSource().getLocation()

La versión de Jon falla cuando el ClassLoader del objeto está registrado como null que parece implicar que fue cargado por Boot ClassLoader .

Este método se ocupa de ese problema:

 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"; } 

Editar solo 1ra línea: Main .class

 Class c = Main.class; String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", ""); System.out.println(path); 

Salida:

 /C:/Users/Test/bin/ 

¡Tal vez un mal estilo pero funciona bien!

Eche un vistazo a esta pregunta similar. Herramienta para descubrir la misma clase …

Creo que el obstáculo más relevante es si tienes un cargador de clases personalizado (cargando desde un db o ldap)

Por lo general, no tenemos qué usar hardcoding. Primero podemos obtener className y luego usar ClassLoader para obtener la URL de la clase.

  String className = MyClass.class.getName().replace(".", "/")+".class"; URL classUrl = MyClass.class.getClassLoader().getResource(className); String fullPath = classUrl==null ? null : classUrl.getPath(); 

Este enfoque funciona tanto para archivos como para jar

 Class clazz = Class.forName(nameOfClassYouWant); URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class"); InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish 

Suponiendo que está trabajando con una clase llamada MyClass , lo siguiente debería funcionar:

 MyClass.class.getClassLoader(); 

Si puede o no obtener la ubicación en disco del archivo .class depende del mismo cargador de clases. Por ejemplo, si está usando algo como BCEL, una clase determinada puede no tener una representación en disco.