Я пытаюсь настроить пользовательский загрузчик классов, который перехватывает классы для печати, какие классы загружаются в приложение. Этот загрузчик выглядит следующим образом:
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("Loading: " + name);
return super.loadClass(name);
}
}
Он просто выплескивает имя всех классов, которые он загружает. Однако, когда я пытаюсь запустить некоторый код,
import org.python.util.PythonInterpreter;
public class Scripts {
public String main(){
PythonInterpreter p = new PythonInterpreter();
p.exec("print 'Python ' + open('.gitignore').read()");
return "Success! Nothing broke";
}
}
с помощью
MyClassLoader bcl = new MyClassLoader();
Class c = bcl.loadClass("Scripts");
Method m = c.getMethod("main");
String result = (String) m.invoke(c.getConstructor().newInstance());
выводит
Loading: Scripts
Loading: java.lang.Object
Loading: java.lang.String
Loading: org.python.util.PythonInterpreter
Python build/
.idea/*
*.iml
RESULT: Success! Nothing broke
Что кажется довольно странным. org.python.util.PythonInterpreter
не является простым классом, и он зависит от целой группы других классов в пакете org.python.util
. Эти классы явно загружаются, поскольку код exec
'd python способен делать вещи и читать мой файл. По какой-то причине эти классы не загружаются загрузчиком классов, загружаемым PythonInterpreter
.
Почему? У меня создалось впечатление, что загрузчик классов, используемый для загрузки класса C
, будет использоваться для загрузки всех других классов, необходимых для C
, но это явно не происходит здесь. Это ошибочное предположение? Если это так, как мне настроить его таким образом, чтобы все транзитивные зависимости C
загружались моим загрузчиком классов?
EDIT:
Некоторые эксперименты с использованием URLClassLoader
, которые были предложены. Я изменил делегацию в loadClass()
:
try{
byte[] output = IOUtils.toByteArray(this.getResourceAsStream(name));
return instrument(defineClass(name, output, 0, output.length));
}catch(Exception e){
return instrument(super.loadClass(name));
}
а также сделать подкласс MyClassLoader URLClassLoader, а не простой ClassLoader, захватить URL-адреса с помощью:
super(((URLClassLoader)ClassLoader.getSystemClassLoader()).getURLs());
Но это не кажется правильным. В частности, getResourceAsStream()
бросает на него значения null для всех классов, которые я запрашиваю, даже несистемные классы, подобные Jython lib.