>> Try look at the super simple example attached below.
>
[quoted text clipped - 38 lines]
>
>> }
Please don't top post, it makes it hard to understand whats going on...
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. While your
application may be a good candidate, there are dangers of using reflection:
<http://virtualinfinity.net/wordpress/program-design/2007/01/11/the-dangers-of-re
flection-or-put-down-that-mirror/>
Hope this helps,
Daniel.

Signature
Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
>> 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.
>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/>
Aryeh M. Friedman - 03 Oct 2007 23:42 GMT
> while (true) {
> long lastMod = classFile.lastModified();
[quoted text clipped - 8 lines]
> classTimestamp = lastMod;
> }
That is almost identical (and functionally so) to my test case:
while(true)
{
loadClass();//handles all the nasty details of loading the class
including new URLCloassLoader
Aryeh M. Friedman - 03 Oct 2007 23:46 GMT
> while (true) {
> long lastMod = classFile.lastModified();
[quoted text clipped - 12 lines]
> Thread.currentThread().sleep(10 * 1000);
> }
This is functionally identical to the following (which is the test
code that lead me to make the comment about externally compiled
classes):
while(true) {
testClassLoader(); // create a new class loader and load class
System.out.println("hnit any key to reload");
System.in();
}
new timestamps *DO NOT* help.... the only solution I have found is to
read the binary class file and then link it to symbol table with
ClassLoader.defineClass (btw this is the solution JUnit uses)).
Mark Rafn - 04 Oct 2007 00:23 GMT
>> if (lastMod > classTimestamp) {
>> // if classfile is new, load it.
[quoted text clipped - 9 lines]
>> System.out.println("message: " + generator.getMessage());
>> Thread.currentThread().sleep(10 * 1000);
>This is functionally identical to the following (which is the test
>code that lead me to make the comment about externally compiled
>classes):
Sure, there's lots of ways to do it. However, if you're having trouble with
classes not getting reloaded, my example shows that it has NOTHING to do with
casting before use, or "external" compilation.
>new timestamps *DO NOT* help.
They're just one possible mechanism for determining that the class has
changed. I used them because someone said they were having problems with
reloading classes and wanted to detect when a file changed.
>.. the only solution I have found is to
>read the binary class file and then link it to symbol table with
>ClassLoader.defineClass (btw this is the solution JUnit uses)).
JUnit may do that for it's own convenience, and perhaps for bytecode
manipulation as it loads stuff. Or maybe so it can force loading classes that
have the same package and classname as something the parent classloader can
see. It's absolutely not necessary for normal class loading.
--
Mark Rafn dagon@dagon.net <http://www.dagon.net/>