ClassLoader not loading recompiled classes

Discussion in 'Java' started by Aryeh M. Friedman, Oct 2, 2007.

  1. 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
     
    Aryeh M. Friedman, Oct 2, 2007
    #1
    1. Advertising

  2. Aryeh M. Friedman

    Daniel Pitts Guest

    On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    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.
     
    Daniel Pitts, Oct 2, 2007
    #2
    1. Advertising

  3. On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    > On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    > 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?
     
    Aryeh M. Friedman, Oct 2, 2007
    #3
  4. Aryeh M. Friedman wrote:
    > On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    >> On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    >> 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.

    Regards,

    Silvio Bierman
     
    Silvio Bierman, Oct 2, 2007
    #4
  5. On Oct 2, 7:56 am, Silvio Bierman <> wrote:
    > Aryeh M. Friedman wrote:
    > > On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    > >> On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    > >> 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
     
    Aryeh M. Friedman, Oct 2, 2007
    #5
  6. On Oct 2, 9:04 am, "Aryeh M. Friedman" <>
    wrote:
    > On Oct 2, 7:56 am, Silvio Bierman <> wrote:
    >
    >
    >
    > > Aryeh M. Friedman wrote:
    > > > On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    > > >> On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    > > >> 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 ;=)]
     
    Aryeh M. Friedman, Oct 2, 2007
    #6
  7. Aryeh M. Friedman wrote:
    > On Oct 2, 7:56 am, Silvio Bierman <> wrote:
    >> Aryeh M. Friedman wrote:
    >>> On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    >>>> On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    >>>> 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
     
    Silvio Bierman, Oct 2, 2007
    #7
  8. On Oct 2, 9:28 am, Silvio Bierman <> wrote:
    > Aryeh M. Friedman wrote:
    > > On Oct 2, 7:56 am, Silvio Bierman <> wrote:
    > >> Aryeh M. Friedman wrote:
    > >>> On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    > >>>> On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    > >>>> 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)
     
    Aryeh M. Friedman, Oct 2, 2007
    #8
  9. Aryeh M. Friedman wrote:
    > On Oct 2, 9:28 am, Silvio Bierman <> wrote:
    >> Aryeh M. Friedman wrote:
    >>> On Oct 2, 7:56 am, Silvio Bierman <> wrote:
    >>>> Aryeh M. Friedman wrote:
    >>>>> On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    >>>>>> On Oct 1, 10:53 pm, "Aryeh M. Friedman" <>
    >>>>>> 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
     
    Silvio Bierman, Oct 2, 2007
    #9
  10. Aryeh M. Friedman wrote:
    > On Oct 2, 7:56 am, Silvio Bierman <> wrote:
    >> Aryeh M. Friedman wrote:
    >>> On Oct 2, 6:02 am, Daniel Pitts <> wrote:
    >>>> 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.

    >
    > 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);
    }
    }
    }
     
    =?ISO-8859-1?Q?Arne_Vajh=F8j?=, Oct 2, 2007
    #10

  11. > 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);
    > }
    > }
    >
    > }
     
    Aryeh M. Friedman, Oct 3, 2007
    #11
  12. Aryeh M. Friedman

    Daniel Pitts Guest

    Aryeh M. Friedman wrote:
    >> 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/wordpress/program-design/2007/01/11/the-dangers-of-reflection-or-put-down-that-mirror/>

    Hope this helps,
    Daniel.
    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
     
    Daniel Pitts, Oct 3, 2007
    #12
  13. Aryeh M. Friedman

    Piotr Kobzda Guest

    Aryeh M. Friedman wrote:
    >> 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.


    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
     
    Piotr Kobzda, Oct 3, 2007
    #13
  14. Aryeh M. Friedman

    Mark Rafn Guest

    >> Try look at the super simple example attached below.

    Aryeh M. Friedman <> 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 <> 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 <http://www.dagon.net/>
     
    Mark Rafn, Oct 3, 2007
    #14

  15. > 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
     
    Aryeh M. Friedman, Oct 3, 2007
    #15
  16. > 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)).
     
    Aryeh M. Friedman, Oct 3, 2007
    #16
  17. Aryeh M. Friedman

    Mark Rafn Guest

    Aryeh M. Friedman <> wrote:
    >> 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.
    --
    Mark Rafn <http://www.dagon.net/>
     
    Mark Rafn, Oct 4, 2007
    #17
  18. Aryeh M. Friedman wrote:
    >> 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.


    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
     
    =?ISO-8859-1?Q?Arne_Vajh=F8j?=, Oct 4, 2007
    #18
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. =?Utf-8?B?QXNwLm5ldCBwYWdlIG5vdCByZWNvbXBpbGVk?=

    Asp.net page not recompiled

    =?Utf-8?B?QXNwLm5ldCBwYWdlIG5vdCByZWNvbXBpbGVk?=, Jan 30, 2004, in forum: ASP .Net
    Replies:
    1
    Views:
    355
    Ken Cox [Microsoft MVP]
    Jan 31, 2004
  2. amw
    Replies:
    1
    Views:
    3,007
    Chris Smith
    Sep 25, 2003
  3. Erwin Moller
    Replies:
    6
    Views:
    2,717
    Chris Smith
    May 27, 2004
  4. jortizclaver
    Replies:
    2
    Views:
    390
    Keith Thompson
    Feb 22, 2006
  5. jortizclaver
    Replies:
    0
    Views:
    308
    jortizclaver
    Feb 22, 2006
Loading...

Share This Page