I am writing a server program which is used to run unit tests of an API (displaying lots of information and providing web access to control / monitor the whole thing)...<
Yes. I've seen it done at a NFJS conference. It's how things like web containers support hot deployment of applications and involves taking advantage of the scope of class loaders. In order to accomplish it you need to create a new class loader and use that to load the library in question.. then throw the loader away (or not) and create another when you want to reload. You may also have to override the behaviour of the class loader (I remember something about class loaders getting classes via their parent first by default.) Also, I remember a warning that objects created by different class loaders are not compatible (not of the same type) with each other even if the .class file is exactly the same.
It's mostly deep magic to me though. ;-)
I think if you load a class using
Class.forName(clsname, init, classloader);
(Javadoc here) you will get an instance of the class provided by the given classloader. Everything loaded because of that class will also be loaded via the same classloader.
As long as you're very careful with the objects instantiated from this point on (to allow for GC), you should be able to reload different versions. I did this once before with Java 1.3, it took a lot of debugging, but at the end I had a "bootstrap" application that loaded a Runnable
class by name and was able to "soft-restart" by instantiating a new classloader against a different URL and going again.
You could programatically modify your classpath to reflect your JAR changes. Here is how I would do it:
URLClassLoader urlClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
Method m = URLClassLoader.class.getDeclaredMethod("addURL", new Class[]{URL.class});
m.setAccessible(true);
m.invoke(urlClassLoader, jarFile.toURI().toURL());
String cp = System.getProperty("java.class.path");
if (cp != null) {
cp += File.pathSeparatorChar + jarFile.getCanonicalPath();
} else {
cp = jarFile.toURI().getPath();
}
System.setProperty("java.class.path", cp);
where jarFile is the version of the jar you want to use/overwrite.
Probably not. The Java classloader doesn't really support run-time loading; even the available classloaders are hacks that use a proxy object.
OSGi is a framework that will allow you to do it. JSR 277 the Java Module System is designed for doing that as well (I think). I have not followed the OSGi -vs- JSR 277 debate, so I don't know f they are trying to marge them at all.
You can roll your own with class loaders, but it'll be less "fun".
You can use the opensource package : JclLoader which helps in loading different versions of the same jar. This was also a need in one of our systems to do testing .
Link: http://sourceforge.net/projects/jcloader/