I am writing a library where I allow people to provide implementations of certain interfaces using a plugin framework (it's JPF if you're familiar). The plugins are not stored in the classpath. The framework gives me a ClassLoader for each plugin, so when implementation named "MyImpl" of interface "MyInterface" is requested, I can find the correct plugin, and then use that plugin's ClassLoader to load the class, from which I can make an instance if I know something about the constructor. So far so good.
However, now I have a case where I need to call a method that is only available on that particular implementation. So, there are two ways I could try to do this:
Method 1:
// Makes sure that MyImpl has been loaded, using the custom classloader
Plugins.getClass(MyInterface.class, "MyImpl");
// This line will not compile because MyImpl is not available at build time
MyImpl foo = new MyImpl();
// If I could get this far, this line would work:
foo.methodOnlyInMyImpl();
Method 2:
// This call will get an instance of MyImpl (already written and tested)
MyInterface foo = Plugins.getInstance(MyInterface.class, "MyImpl");
// Compiler error because there is no MyInterface.methodOnlyInMyImpl method.
foo.methodOnlyInMyImpl()
Method 1 is the cleaner of the two, as it is most similar to how you would write the code if the class were "normal" and not accessible via a plugin. However, neither compiles.
Options I've come up with so far:
A. Use Method 2, but use reflection to do the methodOnlyInMyImpl method call (please, no!)
B. Place the plugin classes in the build path and then use Method 1, which would compile. (my current favorite)
C. B + when plugins are installed, copy the classfiles to another directory that is in the classpath, so the system classloader can load them (causes other problems)
So, my questions are:
- Am I missing another idea that's better?
- If I do B, will I have problems at runtime? After all, the class using MyImpl will presumably have been loaded using the system classloader. So, as soon as it sees
MyImpl foo
, won't it try to load MyImpl using the system classloader, which will fail (even though the Plugins.newInstance call would provide an instance of MyImpl)?