Carregador de classe Java personalizado não está sendo usado para carregar dependências?
Eu tenho tentado configurar um classloader personalizado que intercepta classes para imprimir quais classes estão sendo carregadas no aplicativo. O classloader se parece com isso
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
System.out.println("Loading: " + name);
return super.loadClass(name);
}
}
Ele apenas mostra o nome de todas as classes que ele carrega. No entanto, quando tento executar algum código,
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";
}
}
através da
MyClassLoader bcl = new MyClassLoader();
Class c = bcl.loadClass("Scripts");
Method m = c.getMethod("main");
String result = (String) m.invoke(c.getConstructor().newInstance());
imprime
Loading: Scripts
Loading: java.lang.Object
Loading: java.lang.String
Loading: org.python.util.PythonInterpreter
Python build/
.idea/*
*.iml
RESULT: Success! Nothing broke
O que parece um pouco estranho.org.python.util.PythonInterpreter
não é uma classe simples, e depende de um monte de outras classes noorg.python.util
pacote. Essas classes estão claramente sendo carregadas, para oexec
O código python é capaz de fazer coisas e ler meu arquivo. Por alguma razão, no entanto, essas classes não estão sendo carregadas pelo carregador de classes que foi carregadoPythonInterpreter
.
Por que é que? Fiquei com a impressão de que o classloader usado para carregar uma classeC
seria usado para carregar todas as outras classes necessáriasC
, mas isso claramente não está acontecendo aqui. Essa suposição está errada? Se for, como configurá-lo de tal forma que todas as dependências transitivas deC
são carregados pelo meu classloader?
EDITAR:
Algumas experiências com o usoURLClassLoader
, o que foi sugerido. Eu modifiquei a delegação emloadClass()
:
try{
byte[] output = IOUtils.toByteArray(this.getResourceAsStream(name));
return instrument(defineClass(name, output, 0, output.length));
}catch(Exception e){
return instrument(super.loadClass(name));
}
bem como fez MyClassLoader subclasse URLClassLoader em vez de simples ClassLoader, pegando URLs via:
super(((URLClassLoader)ClassLoader.getSystemClassLoader()).getURLs());
Mas isso não parece ser a coisa certa. Em particular,getResourceAsStream()
está lançando nulos de volta para mim para todas as classes que estou solicitando, mesmo classes não-sistema como o Jython lib.