tags:

views:

1374

answers:

7

Hello!

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

This API is known to the server during compile time and is provided as a JAR.

To be able to compare between unit test results of different versions of the API (without restarting the server), I want to be able to unload the 'current' version of the API, and to reload a newer one (or an older one).

I don't want to use URLClassLoader and invoke every single method by name
( using getDeclaredMethod("someMethod") ),
because the server heavily depends on the API and it would be complicated to 'wrap' every method call in such dirty way.

I was thinking: Since all interfaces of all versions of the JAR are same, couldn't I do it by somehow reloading an other version of the JAR (without that by-name-invokation?).

Note: I am using latest Java SE (6) and Java EE (5).

If you think, what I'm trying to achieve is not possible, please suggest a 'workaround' or a different concept.

A: 

Probably not. The Java classloader doesn't really support run-time loading; even the available classloaders are hacks that use a proxy object.

Don Werve
+2  A: 

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.

Steve Reed
+2  A: 

A similar question has been asked (and answered) before:

http://stackoverflow.com/questions/148681/unloading-classes-in-java

sleske
+1  A: 

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

TofuBeer
A: 

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. ;-)

Chris Nava
A: 

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.

Flueras Bogdan
A: 

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/

techzen