Я пытаюсь настроить пользовательский загрузчик классов, который перехватывает классы для печати, какие классы загружаются в приложение. Этот загрузчик выглядит следующим образом:
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.