Hello all, first post here so please forgive me if I'm not posting in the right place. I'm also not an english native speaker :roll:
Anyway, I've got this little app where I need to support plugins; the objective here is that a programmer can implement an interface and simply add the class to the classpath, and the app will load it.
The way I'm currently doing is, right after starting, querying System.getProperty("java.class.path") and searching for all classes there that implement this interface I want:
The ClassFinder class can be found here (please note that I'm not the author, and simply copied it from somewhere to my project's svn).
If I run the app from inside eclipse, everything works just fine - all the classes are found and can be used. If, however, I use ant to pack them (they are packed in several different .jar files), nothing is returned.
One thing I noticed when debugging is that running inside eclipse java.class.path returns the current (correct) classpath; however, if I get java.class.path when packed, it returns only the name of the launched jar (f2s-main.jar, in this case). Shouldn't it return everything that is set in the MANIFEST.MF Class-Path attribute? I do think that is set correctly because I can use other classes from these packages in the code.
You could try reading the Manifest using java.util.jar.Manifest:
You can use getMainAttributes and getEntries to find the value.
There is one problem though: resource /META-INF/MANIFEST.MF can quite well point to the manifest file of another JAR file if that is loaded first! For example, a JAR file in the /lib/ext folder of the JRE.
I'm still working on a way to get access to the right manifest file.
How this works:
- get a resource to the class file itself (only works for sure with the system class loader and URL class loader)
- strip off the part leading to the class; what remains is the root for this JAR file
- add META-INF/MANIFEST.MF
- create a new URL and open a stream to it
For example, this URL becomes
The rest is pretty much the same.
Now this code lacks a lot of stability; if the class is not run from a JAR file it will fail miserable when opening the stream because the URL does not exist. Also, the exception handling is not handled at all. But I'm sure you can figure out how to handle this.
Joined: Jan 10, 2009
Rob's implementation worked perfectly. The only "but" is that I need to know the class at runtime, so I passed a String argument and used:
My modifications to ClassFinder (the original Burt Beckwith/Michael Stover class for Jakarta Jmeter) can be found here.
Marcelo Schneider wrote:Rob's implementation worked perfectly. The only "but" is that I need to know the class at runtime, so I passed a String argument and used:
And that's of course the right way to go ;) Although technically you should check the result of lastIndexOf against -1 in case it's a class in the default package.
You of course do something similar with the removal part:
Joined: Jan 10, 2009
Sorry to bring this topic back up, but any ideas if I want to run it from Java Web Start? I mean, it renames all downloaded jars, so the whole "java.class.path" or manifest approach is quite useless...
That idea you originally had keeps falling on its face every time you try it in a new environment, doesn't it? To me that means it wasn't a very good idea.
A typical way to support plugins is that the plugin consists of a manifest file which lists the plugin classes, plus the classes themselves. Then to load them you first get the manifest, and then load all the classes which it lists. A lot easier than trying to search the entire classpath.