ClassLoader not loading recompiled classes

  • Thread starter Aryeh M. Friedman
  • Start date
A

Aryeh M. Friedman

ClassLoader does not update class on recompile:

Script started on Tue Oct 2 01:45:20 200
cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();

System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}
}
cat MyClass.java
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}
}
javac *.java
java Main
not hi there
hit any key to reload/rerun MyClass

not hi there
hit any key to reload/rerun MyClass
^Z
Suspended
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}
}
mv foo MyClass.java
javac MyClass.java
fg
java Main

not hi there
hit any key to reload/rerun MyClass
^C
Script done on Tue Oct 2 01:47:02 200
 
D

Daniel Pitts

ClassLoader does not update class on recompile:

Script started on Tue Oct 2 01:45:20 200> cat Main.java

public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();

System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
cat MyClass.java

public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
javac *.java
java Main

not hi there
hit any key to reload/rerun MyClass

not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo

public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
mv foo MyClass.java
javac MyClass.java
fg

java Main

not hi there
hit any key to reload/rerun MyClass
^C> exit

Script done on Tue Oct 2 01:47:02 200

Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.

Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.
 
A

Aryeh M. Friedman

ClassLoader does not update class on recompile:
Script started on Tue Oct 2 01:45:20 200> cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();
System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
not hi there
hit any key to reload/rerun MyClass
not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
java Main
not hi there
hit any key to reload/rerun MyClass
^C> exit
Script done on Tue Oct 2 01:47:02 200

Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.

Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.

Since I am relativally naive with class loaders how do I create a new
instance of the system class loader?
 
S

Silvio Bierman

Aryeh said:
ClassLoader does not update class on recompile:
Script started on Tue Oct 2 01:45:20 200> cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();
System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
cat MyClass.java
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
javac *.java
java Main
not hi there
hit any key to reload/rerun MyClass
not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
mv foo MyClass.java
javac MyClass.java
fg
java Main
not hi there
hit any key to reload/rerun MyClass
^C> exit
Script done on Tue Oct 2 01:47:02 200
Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.

Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.

Since I am relativally naive with class loaders how do I create a new
instance of the system class loader?

You don't. You can write your own class loaders if you want and can
implement any loading behavior you think is suitable.

Beware that class-reloading introduces all kinds of behavior that is
counter-intuitive. Multiple instances of what appears to be the same
static variable thereby also breaking singleton patterns in your code
(which are broken already, but that is a completely different matter) is
only one example.

Please start by telling us what the real problem is that you need to
solve. Going the class-loader way is probably among the worst solutions
for your problem.

Regards,

Silvio Bierman
 
A

Aryeh M. Friedman

Aryeh said:
On Oct 1, 10:53 pm, "Aryeh M. Friedman" <[email protected]>
wrote:
ClassLoader does not update class on recompile:
Script started on Tue Oct 2 01:45:20 200> cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();
System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
cat MyClass.java
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
javac *.java
java Main
not hi there
hit any key to reload/rerun MyClass
not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
mv foo MyClass.java
javac MyClass.java
fg
java Main
not hi there
hit any key to reload/rerun MyClass
^C> exit
Script done on Tue Oct 2 01:47:02 200
Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.
Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.
Since I am relativally naive with class loaders how do I create a new
instance of the system class loader?

You don't. You can write your own class loaders if you want and can
implement any loading behavior you think is suitable.

Beware that class-reloading introduces all kinds of behavior that is
counter-intuitive. Multiple instances of what appears to be the same
static variable thereby also breaking singleton patterns in your code
(which are broken already, but that is a completely different matter) is
only one example.

Please start by telling us what the real problem is that you need to
solve. Going the class-loader way is probably among the worst solutions
for your problem.

I wrote a gui based unit testing framework and it loads the top level
test suites from a text box with there names in it (initially
populated from command line)... I do not want to have to close/reopen
the app when I rewrite/recompile some code under test.

--Aryeh
 
A

Aryeh M. Friedman

Aryeh said:
On Oct 1, 10:53 pm, "Aryeh M. Friedman" <[email protected]>
wrote:
ClassLoader does not update class on recompile:
Script started on Tue Oct 2 01:45:20 200> cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();
System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
cat MyClass.java
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
javac *.java
java Main
not hi there
hit any key to reload/rerun MyClass
not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
mv foo MyClass.java
javac MyClass.java
fg
java Main
not hi there
hit any key to reload/rerun MyClass
^C> exit
Script done on Tue Oct 2 01:47:02 200
Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.
Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.
Since I am relativally naive with class loaders how do I create a new
instance of the system class loader?
You don't. You can write your own class loaders if you want and can
implement any loading behavior you think is suitable.
Beware that class-reloading introduces all kinds of behavior that is
counter-intuitive. Multiple instances of what appears to be the same
static variable thereby also breaking singleton patterns in your code
(which are broken already, but that is a completely different matter) is
only one example.
Please start by telling us what the real problem is that you need to
solve. Going the class-loader way is probably among the worst solutions
for your problem.

I wrote a gui based unit testing framework and it loads the top level
test suites from a text box with there names in it (initially
populated from command line)... I do not want to have to close/reopen
the app when I rewrite/recompile some code under test.

If you want to see the actual thing in action you can download it from
http://www.flosoft-systems.com/order.php (sorry but due to legal
restrictions I can not give out the direct download link... for
"purpose" just put in "classloader issue from c.l.j.p" and the rest of
the data I can careless about [unless your of course going to buy it
after the trial peroid is over ;=)]
 
S

Silvio Bierman

Aryeh said:
Aryeh said:
On Oct 1, 10:53 pm, "Aryeh M. Friedman" <[email protected]>
wrote:
ClassLoader does not update class on recompile:
Script started on Tue Oct 2 01:45:20 200> cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();
System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
cat MyClass.java
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
javac *.java
java Main
not hi there
hit any key to reload/rerun MyClass
not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
mv foo MyClass.java
javac MyClass.java
fg
java Main
not hi there
hit any key to reload/rerun MyClass
^C> exit
Script done on Tue Oct 2 01:47:02 200
Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.
Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.
Since I am relativally naive with class loaders how do I create a new
instance of the system class loader?
You don't. You can write your own class loaders if you want and can
implement any loading behavior you think is suitable.

Beware that class-reloading introduces all kinds of behavior that is
counter-intuitive. Multiple instances of what appears to be the same
static variable thereby also breaking singleton patterns in your code
(which are broken already, but that is a completely different matter) is
only one example.

Please start by telling us what the real problem is that you need to
solve. Going the class-loader way is probably among the worst solutions
for your problem.

I wrote a gui based unit testing framework and it loads the top level
test suites from a text box with there names in it (initially
populated from command line)... I do not want to have to close/reopen
the app when I rewrite/recompile some code under test.

--Aryeh

Is there any need to run the tests in-process? You could spawn an
external java process to run the tests and have it store the test
results in a place where the GUI can find it.

Gr.

Silvio
 
A

Aryeh M. Friedman

Aryeh said:
Aryeh M. Friedman wrote:
On Oct 1, 10:53 pm, "Aryeh M. Friedman" <[email protected]>
wrote:
ClassLoader does not update class on recompile:
Script started on Tue Oct 2 01:45:20 200> cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();
System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
cat MyClass.java
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
javac *.java
java Main
not hi there
hit any key to reload/rerun MyClass
not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
mv foo MyClass.java
javac MyClass.java
fg
java Main
not hi there
hit any key to reload/rerun MyClass
^C> exit
Script done on Tue Oct 2 01:47:02 200
Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.
Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.
Since I am relativally naive with class loaders how do I create a new
instance of the system class loader?
You don't. You can write your own class loaders if you want and can
implement any loading behavior you think is suitable.
Beware that class-reloading introduces all kinds of behavior that is
counter-intuitive. Multiple instances of what appears to be the same
static variable thereby also breaking singleton patterns in your code
(which are broken already, but that is a completely different matter) is
only one example.
Please start by telling us what the real problem is that you need to
solve. Going the class-loader way is probably among the worst solutions
for your problem.
I wrote a gui based unit testing framework and it loads the top level
test suites from a text box with there names in it (initially
populated from command line)... I do not want to have to close/reopen
the app when I rewrite/recompile some code under test.

Is there any need to run the tests in-process? You could spawn an
external java process to run the tests and have it store the test
results in a place where the GUI can find it.

Gr.

Silvio

In theory no but it sounds a little kludgist and perhaps not portable
(I don't see how it wouldn't be but once you ask the OS for anything I
get nervious)
 
S

Silvio Bierman

Aryeh said:
Aryeh said:
Aryeh M. Friedman wrote:
On Oct 1, 10:53 pm, "Aryeh M. Friedman" <[email protected]>
wrote:
ClassLoader does not update class on recompile:
Script started on Tue Oct 2 01:45:20 200> cat Main.java
public class Main
{
public static void main(String[] args)
throws Throwable
{
while(true) {
ClassLoader loader=ClassLoader.getSystemClassLoader();
Class klass=loader.loadClass("MyClass");
MyClass mc=(MyClass) klass.newInstance();
System.out.println("hit any key to reload/rerun MyClass");
System.in.read();
}
}}
cat MyClass.java
public class MyClass
{
public MyClass()
{
System.out.println("not hi there");
}}
javac *.java
java Main
not hi there
hit any key to reload/rerun MyClass
not hi there
hit any key to reload/rerun MyClass
^Z
Suspended> cat foo
public class MyClass
{
public MyClass()
{
System.out.println("foo on you");
}}
mv foo MyClass.java
javac MyClass.java
fg
java Main
not hi there
hit any key to reload/rerun MyClass
^C> exit
Script done on Tue Oct 2 01:47:02 200
Right, a ClassLoader will not re-load a class. You will have to
instantiate a new class loader to do so.
ClassLoader.loadClass will first look for already loaded classes. It
will not re-load the class into the JVM.
Its generally difficult to get dynamic class behavior from Java. You
aren't able to unload a class, and load a different version of it.
Also, and already loaded classes that refer to that other class will
only be able to refer to one instance of it, not one from one class
loader, and then another from another class loader.
Since I am relativally naive with class loaders how do I create a new
instance of the system class loader?
You don't. You can write your own class loaders if you want and can
implement any loading behavior you think is suitable.
Beware that class-reloading introduces all kinds of behavior that is
counter-intuitive. Multiple instances of what appears to be the same
static variable thereby also breaking singleton patterns in your code
(which are broken already, but that is a completely different matter) is
only one example.
Please start by telling us what the real problem is that you need to
solve. Going the class-loader way is probably among the worst solutions
for your problem.
I wrote a gui based unit testing framework and it loads the top level
test suites from a text box with there names in it (initially
populated from command line)... I do not want to have to close/reopen
the app when I rewrite/recompile some code under test.
--Aryeh
Is there any need to run the tests in-process? You could spawn an
external java process to run the tests and have it store the test
results in a place where the GUI can find it.

Gr.

Silvio

In theory no but it sounds a little kludgist and perhaps not portable
(I don't see how it wouldn't be but once you ask the OS for anything I
get nervious)

For this kind of application the ClassLoader woes I mentioned are
probably not relevant. However, you must remember that when you run such
completely generic test code in-process you may (and probably will)
compromise the state of your VM and risk bringing down the application
itself.
I would go the out-of-process way. I do not see why this would not work
in any reasonable Java Runtime env.

Regards,

Silvio
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Aryeh said:
I wrote a gui based unit testing framework and it loads the top level
test suites from a text box with there names in it (initially
populated from command line)... I do not want to have to close/reopen
the app when I rewrite/recompile some code under test.

Try look at the super simple example attached below.

Arne

=============================================

import java.io.*;
import java.net.*;

public class DoubleDynmaic {
private static void dynno(int n) {
(new File("test")).mkdir();
try {
OutputStream os = new FileOutputStream("test/Test.java");
PrintStream ps = new PrintStream(os);
ps.println("public class Test {");
ps.println(" public Test() {");
ps.println(" System.out.println(" + n + ");");
ps.println(" }");
ps.println("}");
ps.close();
os.close();
Runtime.getRuntime().exec("javac -d test
test/Test.java").waitFor();
URL[] url = new URL[1];
url[0] = new URL("file:test/");
URLClassLoader cl = new URLClassLoader(url);
Class.forName("Test", true, cl).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
dynno(i);
}
}
}
 
A

Aryeh M. Friedman

Try look at the super simple example attached below.

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

=============================================

import java.io.*;
import java.net.*;

public class DoubleDynmaic {
private static void dynno(int n) {
(new File("test")).mkdir();
try {
OutputStream os = new FileOutputStream("test/Test.java");
PrintStream ps = new PrintStream(os);
ps.println("public class Test {");
ps.println(" public Test() {");
ps.println(" System.out.println(" + n + ");");
ps.println(" }");
ps.println("}");
ps.close();
os.close();
Runtime.getRuntime().exec("javac -d test
test/Test.java").waitFor();
URL[] url = new URL[1];
url[0] = new URL("file:test/");
URLClassLoader cl = new URLClassLoader(url);
Class.forName("Test", true, cl).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
dynno(i);
}
}

}
 
D

Daniel Pitts

Aryeh said:
Try look at the super simple example attached below.
Arne

=============================================

import java.io.*;
import java.net.*;

public class DoubleDynmaic {
private static void dynno(int n) {
(new File("test")).mkdir();
try {
OutputStream os = new FileOutputStream("test/Test.java");
PrintStream ps = new PrintStream(os);
ps.println("public class Test {");
ps.println(" public Test() {");
ps.println(" System.out.println(" + n + ");");
ps.println(" }");
ps.println("}");
ps.close();
os.close();
Runtime.getRuntime().exec("javac -d test
test/Test.java").waitFor();
URL[] url = new URL[1];
url[0] = new URL("file:test/");
URLClassLoader cl = new URLClassLoader(url);
Class.forName("Test", true, cl).newInstance();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
for(int i = 0; i < 10; i++) {
dynno(i);
}
}
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.
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/wordpres...angers-of-reflection-or-put-down-that-mirror/>

Hope this helps,
Daniel.
 
P

Piotr Kobzda

Aryeh said:
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.

The point is to prevent from loading your externally compiled "things"
with your application's class loaders.

In the Arne's example each Test class is being loaded again because only
the URLClassLoader knows where to find it (its delegation parent loader
-- in the case, the system class loader -- can't reach it). Each try
creates a new instance of the loader, thus there is no connection with
the previously used loader (and a Test class loaded previously) in each
Class.forName() lookup.

To see the difference run the Arne's example with 'test' directory
reachable from the system class loader's class-path, e.g. that way:

java -Xbootclasspath/a:test DoubleDynamic


piotr
 
M

Mark Rafn

Try look at the super simple example attached below.

Aryeh M. Friedman said:
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 said:
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!";
}
}
 
A

Aryeh M. Friedman

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;
}

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
 
A

Aryeh M. Friedman

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

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

Mark Rafn

Aryeh M. Friedman said:
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);
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.
 
?

=?ISO-8859-1?Q?Arne_Vajh=F8j?=

Aryeh said:
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.

It does not matter how the code compiled. as long as it in the
classpath of the new classloader and not in the classpath of the
standard ones.

And no it does not do the same as straight class
loading (you can unload when using your own classloader).

Arne
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,053
Latest member
BrodieSola

Latest Threads

Top