I'm trying to make app to load dynamically certain classes and then invoke startup method, but the problem is that one class cannot invoke method of another because of different ClassLoader, however as I googled already, I created both classloaders with parent. Here's my test class:
public class Plugin {
public static void main(String[] args) throws Exception {
Class<?> fii = loadClass(new File("Fii.class"), "ua.i0xhex.plugin.Fii");
Class<?> goo = loadClass(new File("Goo.class"), "ua.i0xhex.plugin.Goo");
goo.getMethod("hello", new Class<?>[0]).invoke(goo.newInstance(), (Object[]) null);
}
public static Class<?> loadClass(File file, String name) throws Exception {
DLoader loader = new DLoader(Plugin.class.getClassLoader());
byte[] data = toByte(file);
Class<?> clazz = loader.defineClass(name, data);
return clazz;
}
public static byte[] toByte(File file) throws Exception {
FileInputStream inputStream = new FileInputStream(file);
ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
int count;
byte[] bytes = new byte[1024];
while ((count = inputStream.read(bytes, 0, bytes.length)) != -1)
byteOutputStream.write(bytes, 0, count);
inputStream.close();
return byteOutputStream.toByteArray();
}
public static class DLoader extends ClassLoader {
public DLoader(ClassLoader parentLoader) {
super(parentLoader);
}
public Class<?> defineClass(String name, byte[] b) {
return super.defineClass(name, b, 0, b.length);
}
}
}
I have two classes already compiled and copied near my test app. Goo.hello() must print "Hello World" and then invoke Fii.hi().
Output:
Hello World!
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at ua.i0xhex.plugin.Plugin.main(Plugin.java:11)
Caused by: java.lang.NoClassDefFoundError: ua/i0xhex/plugin/Fii
at ua.i0xhex.plugin.Goo.hello(Goo.java:11)
... 5 more
Caused by: java.lang.ClassNotFoundException: ua.i0xhex.plugin.Fii
at java.lang.ClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 6 more
How to make sure that my dynamic loaded classes will have ability to invoke methods of another loaded classes? All works if I make 1 ClassLoader for both classes, but in real work there will be not only one.
Goo.classloaded and methodhello()invoked successfully, butFii.classnot found. If I use sameDLoaderinstance for both loads, then all will work, but if I make different instances, then no.loaderAis parent,loaderBis child. If I first loadFiiwithloaderAand thenGoowithloaderB, this will work. But in another way -FiiwithloaderBandGoowithloaderA- error. That's my problem. I'm trying to make plugin for Bukkit which will load some classes dynamically after decrypting, and I'm aware, that plugins loaded by Bukkit would not be able to interact with my classes. Is there a way to solve this?