Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding jars to an Eclipse plugin at runtime

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.

like image 884
Maria Avatar asked Jan 28 '11 15:01

Maria


People also ask

Why can I not add external JARs in eclipse?

You have selected the JRE System Library in the panel. Un-select that and you will be able to add external jars. You can click on the Classpath or Modulepath to move the control away.

What is a runtime jar?

JAR stands for Java Archive file. It is a platform–independent file format that allows bundling and packaging all files associated with java application, class files, audio, and image files as well. These files are needed when we run an applet program.


2 Answers

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.

  • One way to do this would an optional Import-Package in your plugin's manifest. In this case your plugin will need to be included in the array passed to refreshPackages.
  • Another option would be to use a DynamicImport-Package statement in your plugin's manifest. Dynamic imports are resolved during class loading

Another 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.

like image 159
Andrew Niefer Avatar answered Oct 12 '22 04:10

Andrew Niefer


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");
like image 25
Will Avatar answered Oct 12 '22 05:10

Will