4 Replies Latest reply on Nov 16, 2006 12:38 PM by starksm64

    Problem with javassist + RepositoryClassLoader

    jason.greene

      I am not sure if this has been discovered before, but I noticed an issue when doing dynamic class generation on UnfiedClassLoader3.

      I have some code that basically does (in simplified pseudocode):

      if (!isLoadable(className, loader))
       generate(className, loader)
      
      ... some time later ....
      
      loader.loadClass(className);
      
      


      This leads to the following events in RepositoryClassLoader when a class is generated:

      1. Class is not found, add to blacklist
      2. defineClass() is called by javassist (using method.setAccess())
      3. loadClass is called, and CNFE is returned due to blacklist entry

      Unfortunately defineClass() is final so there is no way to detect this condition within the loader. So, currently I call clearBlacklists() directly on the loader. This, however, is not very efficient because the entire list is being cleared instead of just the one class that is being generated.

      One possible solution, is that we could define an interface for dispatching defineClass calls. The ClassLoader could then implement this interface, and take care of calling the protected definceClass(), as well as perform any needed cleanup. Javassist would then attempt the interface first, and failover to the normal reflective mechanism.

      -Jason

        • 1. Re: Problem with javassist + RepositoryClassLoader
          jason.greene

           

          "jason.greene@jboss.com" wrote:
          I am not sure if this has been
          Unfortunately defineClass() is final so there is no way to detect this condition within the loader. So, currently I call clearBlacklists() directly on the loader. This, however, is not very efficient because the entire list is being cleared instead of just the one class that is being generated.


          I left out that I can remove the class, and the resource directly, however, I am tied to implementation details of the loader, which may change.

          -Jason

          • 2. Re: Problem with javassist + RepositoryClassLoader
            starksm64

            This is why there is a dynamic url notion.

             /** HashSet<UCL> of class loaders in the repository that have a dynamic
             * URL associated with them. Such a class loader is added to every package
             * class loader set in #getPackageClassLoaders(String).
             */
             private HashSet dynamicClassLoaders = new HashSet();
            
            


            A dynamic URL is one that has a dynamic=true query parameter added to the URL. The aop class generation layer uses this to treat the server/tmp/aopdynclasses dir as containing such classes:

             URL tmpURL = tempdir.toURL();
             URL tmpCP = new URL(tmpURL, "?dynamic=true");
            


            Otherwise, putting the classes in a directory associated with the war class loader would also work since it does not use the ucl by default.


            • 3. Re: Problem with javassist + RepositoryClassLoader
              jason.greene

              Doesn't this just fix visibility of the classloader from other loaders in the repository?

              I checked the AOP implementation, and it is currently doing the same process of manually flushing the blacklists.

              I ended up having to create a child URLClassLoader to catch the transient classes, since I can't pollute the top level CL that is present at deploy time (else classes referenced by the one I am generating will end up conflicting with the ones loaded by the tomcat CL). So this obviates my specific need.

              However it is possible that others would run into it, and if there are plans to redesign any of this for the MC, IMO we should consider a public interface for necessary interactions like this.

              • 4. Re: Problem with javassist + RepositoryClassLoader
                starksm64

                 

                "jason.greene@jboss.com" wrote:
                Doesn't this just fix visibility of the classloader from other loaders in the repository?

                From the perspective that a dynamic class loader should be seen as indexed to any package, yes.

                "jason.greene@jboss.com" wrote:

                I checked the AOP implementation, and it is currently doing the same process of manually flushing the blacklists.


                Ok, this looking under the covers, past the ClassLoader api was supposed to be eliminated by the dynamic class loader notion. The dynamic url notion was not well published or tested so I can't complain. We should have the ability to configure caching behavior for a given deployment, but we should not have to step outside of the class loading api to do this. At least the code doing the class loading should not. This is not to say that we better expose the caching and indexing behavior for injection and integration with lifecycle ops via kernel beans.