views:

106

answers:

2

Hi again. I recently made a post http://stackoverflow.com/questions/3079280/update-java-code-during-runtime and after a few hours fiddling around with different example codes and reading tutorials I have run into the following problem:

By using a ClassLoader I have been able to change a local variabe from Class MyVar1 to Class MyVar2 during runtime using the code at http://www.exampledepot.com/egs/java.lang/reloadclass.html, but I have been unable to replace that Class MyVar2 with another version of MyVar2.

Both MyVar1 and MyVar2 implement an interface VarInterface. The main class holds an instance of the variable using the type VarInterface.

I have read several other implementations that claim to be correct but I cannot get this to work. Can anyone see what I'm doing wrong here?

Main class loop:

    while(true){  
        i++;  
        Thread.sleep(1000);  
        ui.ping();  
        if(i > 3)  
            replaceVar();  
    }

replaceVar:

ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader();
    MyClassLoader classLoader = new MyClassLoader(parentClassLoader);
    Class newClass = classLoader.loadClass("MyVar2");
    ui = (VarInterface)newClass.newInstance();

MyClassLoader.loadClass:

public Class<?> loadClass(String what){
    // Get the directory (URL) of the reloadable class
    URL[] urls = null;
    try {
        // Convert the file object to a URL
        File dir = new File(System.getProperty("user.dir")
                +File.separator+"dir"+File.separator);
        URL url = dir.toURL();
        urls = new URL[]{url};
    } catch (MalformedURLException e) {
    }

    // Create a new class loader with the directory
    ClassLoader cl = new URLClassLoader(urls);

    // Load in the class
    Class cls = null;
    try {
        cls = cl.loadClass("MyVar2");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }

    return cls;
}

For the first 3 iterations MyVar1.ping() is called, after that MyVar2.ping() is called ad infinitum, even if I replace the MyVar2.class and MyVar2.java files.

+1  A: 

I am guessing you are using two class loaders. One, the system class loader, with the bulk of your code in it. Your custom class loader uses the system class loader as its parent. You are trying to get the custom class loader to replace a class in the system class loader. In fact the custom class loader will delegate to the parent in preference to loading its own classes.

What you need to do is make sure that the system class loader loads no implementation of the class. Create a class loader that loads an implementation of the class and delegates to the system class loader. To change implementation create another instance of the class loader.

(Using java.net.URLClassLoader.newInstance is probably easier the creating your own class loader implementation.)

Tom Hawtin - tackline
I AM creating a new class loader instance as you can see above in the replaceVar function.The "bulk of the code" consists of the loop as well as the `ping()` function in the MyVar classes as this is just a sandbox experiment at the moment.
Glader
A: 

I managed to solve the problem. I forgot to keep the files out of the classpath which made the ClassLoader read a new instance only if it was of a different class implementing the same interface and not when I replaced the class with a different version.

So basically: problem solved by removing the files from the project and editing them externally.

Glader
If this is the resolution, you should self accept it so it's clear your question has been answered (albeit by yourself).
Software Monkey