Reputation: 5604
I'm working on a Eclipse plugin that needs classes which are not known at compile time. The classes get sent over the network in jar files. I would like to dynamically load those classes at runtime.
I've tried the approach listed here: http://blog.imaginea.com/making-applications-work-together-in-eclipse/
Unfortunately it doesn't have the desired effect. While the classes do get loaded, I can't use them outside the function where I loaded them. I'm guessing it has something to do with using different class loaders.
Any help is appreciated. Even if you tell me, that it is not possible, so I know I don't have to look any further.
Upvotes: 7
Views: 3629
Reputation: 4309
If you make those jars into OSGi bundles (ie, give them a MANIFEST.MF) then you can install them into the OSGi runtime dynamically.
If you add a bundle activator to your plugin, then you can store the org.osgi.framework.BundleContext and then you can do:
Bundle [] newBundle = new Bundle[] { bundleContext.install(location, newJarInputStream) };
packageAdmin.refreshPackages( newBundle );
packageAdmin.resolveBundles( newBundle);
packageAdmin
is an instance of org.osgi.service.packageAdmin.PackageAdmin which is a service you can acquire with BundleContext#getService
The new jars can be entire bundles in their own right, or they can also be bundle fragments that have your plugin as their host. If they are fragments of your bundle then the your bundle (BundleContext#getBundle()
) will need to be included in the array passed to refreshPackages and resolveBundles.
(EDIT classloading)
Class.forName
from your plugin code will only find classes in the newly installed bundles if your plugin has dependencies that will be satisfied by the new bundles once they are resolved.
Import-Package
in your plugin's manifest. In this case your plugin will need to be included in the array passed to refreshPackages
. DynamicImport-Package
statement in your plugin's manifest. Dynamic imports are resolved during class loadingAnother option is to use Bundle.loadClass
(instead of Class.forName)on the bundle objects for your newly installed bundles. This uses the new bundle's classloader so your plugin itself does not need to have a dependency on the new bundles.
Upvotes: 5
Reputation: 6286
I recently did this for a plugin to eclipse:
Here's the salient code
URL[] urls = new URL[]{ new URL("jar", "", "file:" + jarFile.getAbsolutePath() + "!/")};
URLClassLoader cl = URLClassLoader.newInstance(urls, this.getClass().getClassLoader());
Class<?> loadedClass = cl.loadClass("com.whatever.SomeClass");
Upvotes: 2