web-dev-qa-db-fra.com

Trouver où Java la classe est chargée à partir de

Est-ce que quelqu'un sait comment trouver par programme où le classloader Java charge réellement la classe)?

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

Alors, comment puis-je obtenir que le chargeur de classes me dise d'où provient le fichier de classe actuel sur le disque?

Edit: Que se passe-t-il si le chargeur de classes ne parvient pas à charger la classe en raison d'un problème de version (ou autre)? , est-il possible de trouver quel fichier il essaie de lire avant de le lire?

168
luke

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
174
Jon Skeet

Un autre moyen de savoir d'où une classe est chargée (sans manipuler le source) consiste à démarrer Java VM avec l'option: -verbose:class

93
jiriki
getClass().getProtectionDomain().getCodeSource().getLocation();
71
Dave DiFranco

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

26
Jevgeni Kabanov

La version de Jon échoue lorsque l'objet ClassLoader est enregistré en tant que null, ce qui semble impliquer qu'il a été chargé par le 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";
}
16
OldCurmudgeon

Editez juste 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);

Sortie:

/C:/Users/Test/bin/

Peut-être mauvais style mais fonctionne bien!

4
ecerer

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();
1
Hongyang

Jetez un oeil à cette question similaire. Outil pour découvrir la même classe ..

Je pense que l'obstacle le plus important est si vous avez un chargeur de classe personnalisé (chargement à partir d'une base de données ou d'une LDAP)

1
OscarRyz

Cette approche fonctionne à la fois pour les fichiers et les fichiers jars:

Class clazz = Class.forName(nameOfClassYouWant);

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