Найдите, откуда загружается класс java


кто-нибудь знает, как программно узнать, где Java classloader фактически загружает класс?

Я часто работаю над большими проектами, где путь к классам становится очень длинным, и ручной поиск на самом деле не является вариантом. Недавно у меня возникла проблема, когда загрузчик классов загружал неправильную версию класса, потому что он был на пути к классу в двух разных местах.

Итак, как я могу заставить загрузчик классов сказать мне, где на диске находится фактический файл класса откуда?

Edit: что делать, если загрузчик классов на самом деле не удается загрузить класс из-за несоответствия версии (или что-то еще), есть ли в любом случае мы могли бы узнать, какой файл он пытается прочитать, прежде чем он его читает?

10 154

10 ответов:

вот пример:

package foo;

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

это распечатано:

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

другой способ узнать, откуда загружается класс (без манипулирования источником), - это запустить виртуальную машину Java с опцией:-verbose:class

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

вот что мы используем:

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

это будет работать в зависимости от реализации загрузчика классов: getClass().getProtectionDomain().getCodeSource().getLocation()

версия Джона терпит неудачу, когда объект ClassLoader зарегистрирован в качестве null что, похоже, означает, что он был загружен загрузкой ClassLoader.

этот метод имеет дело с этой проблемой:

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

редактировать только 1-ая строка: Main.класс

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

System.out.println(path);

выход:

/C:/Users/Test/bin/

может быть, плохой стиль, но работает отлично!

взгляните на этот подобный вопрос. инструмент для обнаружения того же класса..

Я думаю, что самое важное препятствие - это если у вас есть пользовательский загрузчик классов ( загрузка из БД или ldap )

Как правило, мы не используем жесткое кодирование. Сначала мы можем получить className, а затем использовать ClassLoader для получения URL-адреса класса.

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

этот подход работает как для файлов, так и коробит:

Class clazz = Class.forName(nameOfClassYouWant);

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

предполагая, что вы работаете с классом MyClass, следующее должно работать:

MyClass.class.getClassLoader();

можно ли получить расположение на диске .файл класса зависит от самого загрузчика. Например, если вы используете что-то вроде BCEL, определенный класс может даже не иметь представления на диске.