Trouver où la classe java est chargée


184

Est-ce que quelqu'un sait comment découvrir par programmation d'où le chargeur de classe Java charge réellement la classe?

Je travaille souvent sur de gros projets où le chemin des classes devient très long et la recherche manuelle n'est pas vraiment une option. J'ai récemment eu un problème où le classloader chargeait une version incorrecte d'une classe car il était sur le chemin de classe à deux endroits différents.

Alors, comment puis-je faire en sorte que le chargeur de classe me dise d'où vient le fichier de classe réel sur le disque?

Edit: Qu'en est-il si le chargeur de classe ne parvient pas à charger la classe en raison d'une incompatibilité de version (ou autre chose), est-il possible de savoir quel fichier il essaie de lire avant de le lire?


4
@JarrodRoberson Je ne pense pas que cela devrait être considéré comme un double de stackoverflow.com/questions/11747833/… puisque cette question a été posée en 2008 et cette question a été posée en 2012
lu

Réponses:


189

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

Ceci a imprimé:

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

32
Pour réduire la saisie redondante, on peut également 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 exemple à partir d'un fichier .groovy?
Ondra Žižka

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

1
Pour le BouncyCastleProvidernom complet du paquet est nécessaire cependant.
Pavel Vlasov

3
Il est possible getClassLoader()de revenir null. Voir ici pour une extension de cette méthode pour gérer cela.
OldCurmudgeon

100

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


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

2
@ries Si on n'a pas besoin de faire cela par programme, c'est certainement la voie à suivre, et cela a résolu mon problème. Cependant, le PO avait demandé spécifiquement comment procéder par programme.
SantiBailors

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

4
Oui, bien que cela ne fonctionne pas avec un gestionnaire de sécurité installé et sans les autorisations requises.
Tom Hawtin - tackline

1
FYI, NPE = exception de pointeur nul. HTH!
Evgeni Sergeev

Cette méthode est préférable tant que vous disposez d'une référence à une instance, car vous pouvez charger la même classe à partir de deux emplacements différents.
Miguel Ping

1
Ne fonctionne pas non plus lorsqu'il est appelé depuis un module Java 9+ (ce que vous n'auriez bien sûr pas pu connaître en 2008).
Jeff G

28

Voici ce que nous utilisons:

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

Cela fonctionnera en fonction de l'implémentation de ClassLoader: getClass().getProtectionDomain().getCodeSource().getLocation()


17

La version de Jon échoue lorsque l'objet ClassLoaderest enregistré comme nullce qui semble impliquer qu'il a été chargé par Boot ClassLoader.

Cette méthode traite ce problème:

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

5

Modifier seulement la 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);

Production:

/C:/Users/Test/bin/

Peut-être mauvais style mais fonctionne bien!


3

En règle générale, nous ne savons pas quoi utiliser le codage en dur. 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();

Doit être: URL classUrl = MyClass.class.getClassLoader (). GetResource ("/" + className);
Andrew Coates le

MyClass.class est une partie importante - getClass () peut retourner Proxy! Ensuite, vous pouvez obtenir un nom comme MyClass $$ EnhancerBySpringCGLIB $$ a98db882.class et une URL nulle.
jalmasi le


1

Manière simple:

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

Exemple de sortie:

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

Ou

String obj = "test simple"; System.out.println (obj.getClass (). GetResource (obj.getClass (). GetSimpleName () + ". Class"));

Exemple de sortie:

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


0

Cette approche fonctionne pour les fichiers et les fichiers JAR:

Class clazz = Class.forName(nameOfClassYouWant);

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

-1

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

MyClass.class.getClassLoader();

Le fait que vous puissiez ou non obtenir l'emplacement sur le disque du fichier .class dépend du chargeur de classe 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.


Cela renvoie le ClassLoader utilisé pour charger la classe, n'est-ce pas? Il ne trouve pas où se trouve le fichier .class?
Koray Tugay du

1
Non, ce n'est pas le cas. Le chargeur de classe peut en fait se référer à un chemin de classe complètement différent - cela signifie qu'il sera totalement incapable de retrouver l'emplacement réel de la classe.
Tomáš Zato - Réintégrer Monica
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.