2008-10-22 13 views
145

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

A menudo trabajo en proyectos grandes donde el classpath es muy largo y la búsqueda manual no es realmente una opción. Hace poco tuve un problem 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: ¿Qué pasa si el cargador de clases en realidad no se puede cargar la clase debido a un conflicto de versiones (o algo más), es allí de todos modos hemos encontrado lo que presentaría su tratando de leer antes de que lo lea?

+4

@JarrodRoberson No creo que esto debe ser considerado un duplicado de http://stackoverflow.com/questions/11747833/getting-filesystem-path-of-class-being-executed desde que se hizo esta pregunta en 2008 y esa pregunta fue hecha en 2012 – luke

Respuesta

148

He aquí 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 imprime:

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

Para reducir el tipeo redundante, también se puede usar la versión más corta: 'Test.class.getResource (" Test.class ")', que no repite el nombre del paquete. – meriton

+1

¿Qué sucede si la clase está compilada, p. de un archivo .groovy? –

+23

@meriton: O bien, para sobrevivir refactorinsgs: 'Test.class.getResource (Test.class.getSimpleName() +" .class ")' – leonbloy

-1

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

MyClass.class.getClassLoader(); 

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

+0

Esto devuelve el cargador de clases usado para cargar la clase, ¿no es así? ¿No encuentra dónde está el archivo .class? –

+1

No, no es así. El cargador de clases puede referirse a una ruta de clases completamente diferente, lo que significa que no podrá reah la ubicación real de la clase. –

1

Eche un vistazo a esta pregunta similar. Tool to discover same class..

creo que el obstáculo más relevante es si usted tiene un cargador de clases personalizado (carga desde una base de datos o LDAP)

59
getClass().getProtectionDomain().getCodeSource().getLocation(); 
+4

Sí, aunque no funciona con un administrador de seguridad instalado y sin los permisos necesarios. –

+2

También podría ser NPE ... –

+1

FYI, NPE = Excepción del puntero nulo. HTH! –

25

Esto es lo que usamos:

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

Esto funcionará dependiendo de la implementación cargador de clases: getClass().getProtectionDomain().getCodeSource().getLocation()

84

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

+5

esto funcionó muy bien, y no tiene el problema de tratar con clases con nulo ClassLoader – lexicalscope

+1

Creo que esta debería haber sido la respuesta aceptada. Realmente proporciona una solución adecuada a la pregunta formulada. –

+0

@ries Si no es necesario hacer esto programáticamente, este es definitivamente el camino a seguir, y resolvió mi problema. Sin embargo, el OP había preguntado específicamente cómo hacer esto programáticamente. – SantiBailors

16

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

ofertas de este método con ese tema:

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

Editar acaba de primera 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 mal estilo, pero funciona muy bien!

0

Este enfoque funciona para ambos archivos y tarros:

Class clazz = Class.forName(nameOfClassYouWant); 

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

Por lo general, nosotros no lo utilizamos para codificar. 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(); 
Cuestiones relacionadas