Re: ClassLoader not loading recompiled classes
Try look at the super simple example attached below.
Aryeh M. Friedman <Aryeh.Friedman@gmail.com> wrote:
Works fine *IF* the code is compiled from within the class but if it
is externally compliled it does the same thing as just straight class
loading.
Then you'll have to add timestamp checking or some other notification that
the class needs to be reloaded. Then reload the class as shown, by
throwing away the classloader that has the old version, and creating a
new one to load the new version.
Daniel Pitts <newsgroup.spamfilter@virtualinfinity.net> wrote:
Anyway, my guess is that you're casting the class (MyClass). Doing this
actually loads the class with the same class loader. You can't know
about a class at the Java level without that class being loaded. You're
going to have to use reflection all the way through.
A common pattern is to have an interface in the parent classloader,
and load an implementation from the child. You use reflection to load and
instantiate the implementation from the child classloader, as shown in
the example, but you can cast it to the interface and then use it normally.
What you might be seeing is that it's easy to accidentally load the class into
the parent classloader rather than the child. You have to make sure that the
classes to be reloaded aren't in the classpath of the parent classloader.
Example (using two directories to keep the impl from being loaded by the
parent classloader before the child gets a chance):
create these two files in two directories named reloader and generator
cd reloader; javac Reloader.java
cd ../generator; javac -cp ../reloader MessageGeneratorImpl.java
cd ../reloader; java -cp . Reloader
(on another window/screen)
change MessageGeneratorImpl.java to have a new message.
recompile it as above.
(on original window/screen) watch the output of Reloader change.
==== file reloader/Reloader.java:
import java.io.*;
import java.net.*;
public class Reloader {
public interface MessageGenerator {
public String getMessage();
}
/**
* Load "MessageGeneratorImpl.class", and print it's message. Repeat
* every few seconds whenever the classfile changes.
*/
public static void main(String[] args) throws Exception {
long classTimestamp = 0;
File classFile = new File("../generator/MessageGeneratorImpl.class");
MessageGenerator generator = null;
while (true) {
long lastMod = classFile.lastModified();
if (lastMod > classTimestamp) {
// if classfile is new, load it.
System.out.println("(re)loading MessageGeneratorImpl");
Object o = new URLClassLoader(
new URL[] {new File("../generator").toURL()},
Reloader.class.getClassLoader()).
loadClass("MessageGeneratorImpl").newInstance();
generator = (MessageGenerator)o;
classTimestamp = lastMod;
}
System.out.println("message: " + generator.getMessage());
Thread.currentThread().sleep(10 * 1000);
}
}
}
==== file generator/MessageGeneratorImpl.java:
public class MessageGeneratorImpl implements Reloader.MessageGenerator {
public String getMessage() {
return "Hello there!";
}
}
--
Mark Rafn dagon@dagon.net <http://www.dagon.net/>