1 2 Previous Next 22 Replies Latest reply on Jul 28, 2004 6:18 AM by chiba

    classloaders, loading classes dynamically

    budevik

      I have read all documentation, tutorial, studied samples carefully,
      even Jboss forums and it all only led me to frustration. Javassist is
      really great tool and I need it, but have no idea how to do simple change in
      class and reload it in my program dynamically. I know about classloader's problem,
      I read 4th section of manual 20 times and still got no receipt. Could you share
      example code with me ? I have plain java class A and it loads another
      plain one B. Next I change superclass of B or insert new method. And now I
      just want to use new modified one in A. of course I got cast
      exception. please tell me what is the proper structure? I used
      javassist.Loader and the result is cast exc. or loading the old class (unmodified).

        • 1. Re: classloaders, loading classes dynamically
          chiba

          The JVM dose not allow us to dynamically reload a class.
          If what you need is the dynamic reloading, it is impossible with Javassist (or maybe any other tools).
          What you can do is to load a modified class B with a new copy of class A so that they belong to a separate namespace (i.e. a class loader).

          The JVM's debugger interface provides limited ability for dynamic reloading. It might be helpful.

          • 2. Re: classloaders, loading classes dynamically
            budevik

             

            "chiba" wrote:
            The JVM dose not allow us to dynamically reload a class.
            If what you need is the dynamic reloading, it is impossible with Javassist (or
            maybe any other tools).


            yes I need to load modified class in the same progam at runtime, I supose we have two ways of using Javassist - save class files and use it later or modify and use in runtime. Am I wrong?
            AFAIK Jboss use it, Tapestry, Aspektwerkz and you say it is impossible?
            maybe I didn't wrote it clearly not to _reload_ but _load_ modified class. just use it at once after modification


            What you can do is to load a modified class B with a new copy of class A so that they belong to a separate namespace (i.e. a class loader).


            and that's the point. I have no idea, no sample code, nothing to make me understand how to do it. When I change class, do getClass and try to cast it I got exception (suppose class was loaded before and its hash is diffrent, causing class cast exception).


            The JVM's debugger interface provides limited ability for dynamic reloading. It might be helpful.


            let's assume I have simple program simplest as possible and I do my job in Eclipse IDE. I want only to change anything in class A and use it _in the same program_ of course use it as a new class with new bytecode. How? I don't believe Mr. Chiba there's no way to achieve it :) please help me


            • 3. Re: classloaders, loading classes dynamically
              chiba

              OK, maybe the 4th section of the tutorial should be revised to clarify
              the points (In fact, I assumed that the readers know Java's class loader
              mechansim when I wrote that section.)

              Anyway, to do what you (maybe) want to do, you must create a new
              instance of javassist.Loader (or your own class loader) and run *all*
              your classes including modified ones and not-modified ones with that
              instance of the class loader. Please read Section 4.2 of the tutorial
              again (there was typos; sorry please read a copy on the web site.)

              To use modifeid B with A (I mean, your example), use the following
              MyTranslator:

              public class MyTranslator implements Translator {
               void start(ClassPool pool)
               throws NotFoundException, CannotCompileException { /* ignore */ }
               void onLoad(ClassPool pool, String classname)
               throws NotFoundException, CannotCompileException
               {
               if (classname.equals("B") {
               CtClass cc = pool.get("B");
               cc.setModifiers(Modifier.PUBLIC); // or whatever you want
               }
               }
              }
              


              And run the main class such as:

              public class Main2 {
               public static void main(String[] args) throws Throwable {
               Translator t = new MyTranslator();
               ClassPool pool = ClassPool.getDefault();
               Loader cl = new Loader();
               cl.addTranslator(pool, t);
               cl.run("MyApp", args);
               }
              }
              


              in the regular way (# java Main2 ...).

              MayApp is the name of the class for launching the application using
              modified B. It can be "A" or "B" if "A" or "B" includes main().

              javassist.Loader dynamically(?) modifes the class file of B when
              it is loaded.

              Does this example help you? If so, I'll add this example to the tutorial.

              • 4. Re: classloaders, loading classes dynamically
                budevik

                Dear Chiba, thanks for that example, I knew that trick, but it is pretty useless for me. Please notice that instrumented code has to be inside "runable" class, so I have to fire such a class with "runner" and forward executing to its main method. It's awful drawback for me. I need to use plain class that can give me an instance of modified class. I want to use this mechanism inside other apps not making it the main application flow. if you develop f.e. web-app there's no comfort to run main() methods. I know what I want but do not know how to achieve it. The best solution would be loading all classes but the modified ones normally with standard loader and saving modified ones to f.e. /tmp/classes and load'em from that location with another classloader. but in my code it results of loading unmodified one, I mean first loaded unmodified bytecode overrides the new one or maybe it isn't even loaded because of delegation, so generally it fails. I used example code from ASM site to reload dynamicaly changed class by classloader that loads from bytecode and in Eclipse it works I got aspectized code, but using this in Tomcat fails. Javassist approach to create AOP is powerfull and very expresible but class loading issues makes it almost useless. I know JBoss guys solved it pretty well, but for ordinary user and ordinary purpose it is pain in the neck.

                • 5. Re: classloaders, loading classes dynamically
                  chiba

                  Hi,

                  Your class does not have to provide main() for startup.
                  Instead, you can call any method by the reflection API.
                  For example,

                  Loader cl = new Loader();
                  cl.addTranslator(pool, t);
                  Class c = cl.loadClass(classname);
                  try {
                   c.getDeclaredMethod("start", new Class[] { String[].class })
                   .invoke(null, new Object[] { args });
                  }
                  catch (java.lang.reflect.InvocationTargetException e) {
                   throw e.getTargetException();
                  }
                  


                  This calls startup(String).

                  If the example above does not help, could you give me a reference
                  to the example code you mentioned below?

                  I used example code from ASM site to reload dynamicaly changed class by classloader that loads from bytecode and in Eclipse it works I got aspectized code


                  Chiba

                  • 6. Re: classloaders, loading classes dynamically
                    budevik

                    unfortunately you are wrong :(((

                    I wrote class A with main() that instantiates class B inside that calls its method getModifiedObject(String className). class B uses class C by reflection as you wrote and and invokes its method get(String className)
                    of course there is also Translator added to ClassPool (all in B class). Translator's code is supposed to insert some code to Foo.class. I can see that onLoad fires, so instrumenting takes place, but this what the C class gives to me (by Class.forName(className).new Instance() is an object of unmodified Foo.class :( so chain A->B->C->Foo.class fails. Foo class loaded by C is not the modified one altough B uses C via reflection and uses translator.
                    to me this subject sucks badly. i know it is not javassist fault beacause it concerns generally issue called "how to modify class and use it". i'm totaly exhausted and I'll probably abadon "bytecode manipulation aop" and use "proxy based aop" :((((

                    http://asm.objectweb.org/doc/faq.html#Q5

                    • 7. Re: classloaders, loading classes dynamically
                      batoussa

                      Hi !

                      I'd like to do the same thing, i.e cast a modified class at runtime but i get a ClassCastException too.
                      I understood that this is in java virtual machine specification that when a class is loaded by two classloaders, it can not be cast.

                      So, is there any solution (even if it's forbidden by java specification) ??

                      • 8. Re: classloaders, loading classes dynamically
                        batoussa

                        I've tested the solution proposed by budevik, abd it works ... so use reflection to call ClassLoader class.

                        Regards
                        Batoussa

                        • 9. Re: classloaders, loading classes dynamically
                          budevik

                           

                          "Batoussa" wrote:
                          I've tested the solution proposed by budevik, abd it works ... so use reflection to call ClassLoader class.

                          Regards
                          Batoussa


                          yes it works, but use your code inside web-app and deploy it in container... btw, could you share this code?

                          • 10. Re: classloaders, loading classes dynamically
                            batoussa

                             

                            yes it works, but use your code inside web-app and deploy it in container... btw, could you share this code?


                            Yeah, you're right, the problem comes from Javassist wich cannot found the right class in his pool.
                            Have anyone got any tips in how using javassist in web application ?

                            • 12. Re: classloaders, loading classes dynamically
                              budevik

                               

                              "Batoussa" wrote:
                              Have a look here http://www.jboss.org/index.html?module=bb&op=viewtopic&t=47263&postdays=0&postorder=asc&start=10


                              right I've already seen it but to me it is "magic" solution ;) wanna see better way ? look at Jboss AOP code :] of course I don't want to say javassist sucks because dynamically reloading of classes is pain in the neck and I know it is possible to have it working. anyway if we consider wide use of Javassist in my opinion documentation HAVE TO provide such a example how to use intrumented class _in the same_ program, and it should be universal, usable code, not i.e. to run static loader, because it is useless. most of people run their code in containers without providing such a example set of happy users of Javassist is stricly limited :)

                              • 13. Re: classloaders, loading classes dynamically
                                chiba

                                Hi,

                                This weekend, I reimplemented CtClass#toClass() with using the
                                trick you found at the ASM site. Since I fixed a small problem
                                of the original code at the ASM site, it should probably work with
                                Tomcat although you need a tip for using toClass() with JBoss.

                                Could you try the new toClass() method? It is downloadable
                                from CVS_HEAD and the *revised* tutorial explains how to use it
                                (see Section 4.1). The revised tutorial is included in CVS_HEAD.

                                I hope this is what you exactly need!

                                Thanks,

                                • 14. Re: classloaders, loading classes dynamically
                                  budevik

                                   

                                  "chiba" wrote:
                                  Hi,

                                  This weekend, I reimplemented CtClass#toClass() with using the
                                  trick you found at the ASM site. Since I fixed a small problem
                                  of the original code at the ASM site, it should probably work with
                                  Tomcat although you need a tip for using toClass() with JBoss.


                                  yeah! good work Chiba. standalone application works, but it wasn't shocking since I had the same, but I did some test with jsp in Tomcat 5.0... it worked too! Of course two thing had to be made: injecting user classpath and container's classloader, but I was written in manual, so I don't complain. it is milestone release for me. now my AOP framework will get new perspectives. thanx.



                                  1 2 Previous Next