Найти, откуда загружается класс Java
Кто-нибудь знает, как программно узнать, откуда на самом деле загрузчик классов Java загружает класс?
Я часто работаю над большими проектами, где путь к классам становится очень длинным, и поиск вручную не является подходящим вариантом. У меня недавно была проблема, когда загрузчик классов загружал неправильную версию класса, потому что он находился в пути к классам в двух разных местах.
Итак, как я могу заставить загрузчик классов сказать мне, откуда на диске берется фактический файл класса?
Редактировать: А как насчет того, если загрузчик классов действительно не может загрузить класс из-за несоответствия версий (или чего-то еще), есть ли в любом случае, мы могли бы узнать, какой файл он пытается прочитать, прежде чем он читает его?
12 ответов
Вот пример:
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 VM с помощью опции: -verbose:class
getClass().getProtectionDomain().getCodeSource().getLocation();
Это то, что мы используем:
public static String getClassResource(Class<?> klass) {
return klass.getClassLoader().getResource(
klass.getName().replace('.', '/') + ".class").toString();
}
Это будет работать в зависимости от реализации ClassLoader: 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/
Может быть, плохой стиль, но работает отлично!
Как правило, нам не нужно использовать жесткое кодирование. Сначала мы можем получить className, а затем использовать ClassLoader для получения URL-адреса класса.
String className = MyClass.class.getName().replace(".", "/")+".class";
URL classUrl = MyClass.class.getClassLoader().getResource(className);
String fullPath = classUrl==null ? null : classUrl.getPath();
Посмотрите на этот похожий вопрос. Инструмент для обнаружения того же класса..
Я думаю, что самое важное препятствие, если у вас есть пользовательский загрузчик классов (загрузка из БД или LDAP)
Простой способ:
System.out.println(java.lang.String.class.getResource(String.class.getSimpleName()+". Class"));
Наш пример:
jar: файл:/D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class
Или
String obj = "простой тест"; System.out.println(obj.getClass(). GetResource(obj.getClass(). GetSimpleName () +". Class"));
Наш пример:
jar: файл:/D:/Java/jdk1.8/jre/lib/rt.jar!/java/lang/String.class
Этот подход работает как для файлов, так и для jar-файлов:
Class clazz = Class.forName(nameOfClassYouWant);
URL resourceUrl = clazz.getResource("/" + clazz.getCanonicalName().replace(".", "/") + ".class");
InputStream classStream = resourceUrl.openStream(); // load the bytecode, if you wish
для модульного теста
Если вам нужно местоположение класса с именем Coverage.java , расположенного в пакете com.acme.api
Class clazz = Coverage.class;
ClassLoader loader = clazz.getClassLoader();
String coverageClazzCompiledAbsoluteTargetLocation = loader
.getResource(clazz.getCanonicalName().replace(".", File.separator) + ".class")
.getFile().replace(File.separatorChar + "$", "");
System.out.println(coverageClazzCompiledAbsoluteTargetLocation);
Результат
/home/Joe/repositories/acme-api/target/test-classes/com/acme/api/Coverage.class
Примечание. Поскольку java требует компиляции, вы не можете получить расположение .java (src/main/java/...). Вам нужно скомпилировать .java в .class, поэтому местоположение, если вы используете maven, будет внутри целевой папки .
во время выполнения: JAR
Если вы создадите свое приложение как jar, расположение класса будет расположением jar плюс пакет clazz.
во время выполнения: ВОЙНА
Если вы создадите свое приложение как войну, местоположением класса будет местоположение войны (папка / bin в tomcat) плюс пакет clazz.
Предполагая, что вы работаете с классом с именем MyClass
должно работать следующее:
MyClass.class.getClassLoader();
Доступность расположения файла.class на диске зависит от самого загрузчика классов. Например, если вы используете что-то вроде BCEL, определенный класс может даже не иметь представления на диске.