2008-10-22 5 views
145

Est-ce que quelqu'un sait comment trouver par programme l'endroit où le classloader java charge réellement la classe?Rechercher l'endroit où la classe java est chargée

Je travaille souvent sur de grands projets où le parcours de classe devient très long et la recherche manuelle n'est pas vraiment une option. J'ai récemment eu un problem où le classloader chargeait une version incorrecte d'une classe parce qu'elle se trouvait sur le chemin de classe à deux endroits différents.

Alors, comment puis-je demander au classloader de me dire d'où vient le fichier de classe réel sur le disque?

Edit: Qu'en est-il si le classloader ne fait charger la classe en raison d'une incompatibilité de version (ou autre chose), est là de toute façon nous pourrions trouver ce fichier son en essayant de lire avant qu'il ne le lit?

+4

@JarrodRoberson Je ne pense pas que cela devrait être considéré comme un double de http://stackoverflow.com/questions/11747833/getting-filesystem-path-of-class-being-executed puisque cette question a été posée en 2008 et cette question a été posée en 2012 – luke

Répondre

148

Voici un exemple:

package foo; 

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

Ce imprimé:

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

Pour réduire le typage redondant, on peut aussi utiliser la version plus courte: 'Test.class.getResource (" Test.class ")', qui ne répète pas le nom du paquet. – meriton

+1

Que faire si la classe est compilée, par ex. à partir d'un fichier .groovy? –

+23

@meriton: Ou, pour survivre refactorinsgs: 'Test.class.getResource (Test.class.getSimpleName() +" .class ")' – leonbloy

-1

En supposant que vous travaillez avec une classe nommée MyClass, ce qui suit devrait fonctionner:

MyClass.class.getClassLoader(); 

Que vous ou ne pouvez pas obtenir l'emplacement sur le disque du fichier .class dépend de la classloader lui-même . Par exemple, si vous utilisez quelque chose comme BCEL, une certaine classe peut même ne pas avoir de représentation sur disque.

+0

Cela renvoie le ClassLoader utilisé pour le chargement de la classe, n'est-ce pas? Il ne trouve pas où le fichier .class est? –

+1

Non, ce n'est pas le cas. Le chargeur de classe peut en fait renvoyer à un chemin de classe complètement différent - cela signifie qu'il sera totalement incapable de retrouver l'emplacement réel de la classe. –

1

Jetez un oeil à cette question similaire. Tool to discover same class..

Je pense que l'obstacle le plus pertinent est que si vous avez un classloader personnalisé (chargement à partir d'un db ou ldap)

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

Oui, bien que cela ne fonctionne pas avec un gestionnaire de sécurité installé et sans les autorisations requises. –

+2

Peut également NPE ... –

+1

FYI, NPE = Exception pointeur nul. HTH! –

25

Voici ce que nous utilisons:

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

Cela fonctionne selon la mise en œuvre de ClassLoader: getClass().getProtectionDomain().getCodeSource().getLocation()

84

Une autre façon de savoir où une classe est chargée à partir (sans manipuler la source) est de démarrer la machine virtuelle Java avec l'option: -verbose:class

+5

cela a très bien fonctionné, et n'a pas le problème de traiter avec des classes avec null ClassLoader – lexicalscope

+1

Je pense que cela aurait dû être la réponse acceptée. Il fournit vraiment une bonne solution à la question posée. –

+0

@ries Si vous n'avez pas besoin de faire cela par programme, c'est définitivement la solution, et cela a résolu mon problème. Cependant, le PO avait spécifiquement demandé comment faire cela par programme. – SantiBailors

16

La version de Jon échoue lorsque le ClassLoader de l'objet est enregistré comme null, ce qui semble indiquer qu'il a été chargé par le démarrage ClassLoader.

Cette méthode traite de cette question:

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

Modifier juste 1ère ligne: Main .class

Class<?> c = Main.class; 
String path = c.getResource(c.getSimpleName() + ".class").getPath().replace(c.getSimpleName() + ".class", ""); 

System.out.println(path); 

Sortie:

/C:/Users/Test/bin/ 

le style peut-être mauvais, mais fonctionne très bien!

0

Cette approche fonctionne pour les deux fichiers et bocaux:

Class clazz = Class.forName(nameOfClassYouWant); 

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

En règle générale, nous ne pas quoi utiliser hardcoding. Nous pouvons d'abord obtenir className, puis utiliser ClassLoader pour obtenir l'URL de la classe.

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