2

I am trying to develop a plugin system, which provides a interface to load jar at runtime. Each jar contains a class that extends from a common abstract class. For example:

//BasicPlugin.java
package byv;

abstract class BasicPlugin {
    abstract public int test(int a);
}

I implemented a subclass:

//PluginA.java
package byv;

import byv.BasicPlugin;

public class PluginA extends BasicPlugin {
    @Override
    public int test(int a) {
        return a + a;
    }
}

The subclass above was compiled and packaged into a jar file(PluginA.jar). This jar only contains PluginA.class. And then in the main project I load it using URLClassLoader:

private static void loadTest() throws Exception {
    URL url = new File("PluginA.jar").toURI().toURL();
    URLClassLoader ClassLoader = URLClassLoader.newInstance(new URL[] {url});

    Class<?> clazz = Class.forName("byv.PluginA", true, ClassLoader);

    BasicPlugin obj = (BasicPlugin) clazz.newInstance();
    obj.test(2);
}

I have already added a reference to BasicPlugin in the main project. But errors still occured:

Exception in thread "main" java.lang.IllegalAccessError: class byv.PluginA cannot access its superclass byv.BasicPlugin
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:634)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:277)
    at java.net.URLClassLoader.access$000(URLClassLoader.java:73)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:212)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:205)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:321)
    at java.net.FactoryURLClassLoader.loadClass(URLClassLoader.java:615)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:266)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:264)
    at byv.Main.loadTest1(Main.java:18)
    at byv.Main.main(Main.java:11)

So how can I fix this problem?

BYVoid
  • 358
  • 4
  • 8

2 Answers2

1

Since it is an IllegalAccessError I suggest you make BasicPlugin public to solve the problem. As far as I know the class you defined is package protected. As such it is not accessible from a different class loader. Since that is what you require for your plugin, it makes not sense to make the class anything else than public.

One more thing, URLClassLoader has a second constructor in which you can specify the parent loader. This loader is then used to load the plugin class. In a more complex environment you may want to specify that loader. Currently your code uses more or less the system loader, which is ok in your example, but I don't know what you intend to do later on. BasicPlugin.class.getClassLoader() gives you the right loader for that class for sure.

Raúl Salinas-Monteagudo
  • 3,412
  • 1
  • 24
  • 22
blackdrag
  • 6,413
  • 2
  • 26
  • 38
  • I simply made BasicPlugin public and then the problem was solved. The second parameter is not needed. – BYVoid May 22 '12 at 08:29
1

Pass the classloader context to use when constructing your URLClassLoader instance:

URLClassLoader ClassLoader = URLClassLoader.newInstance(new URL[] {url},
                                                        this.getClassLoader());
rsp
  • 23,135
  • 6
  • 55
  • 69