7 Replies Latest reply on May 7, 2006 11:55 PM by ben.wang

    JBCACHE-604 - Use of AOPPRoxy class name into streaming

    clebert.suconic

      JBossCacheAOP (POJOCache) is using org.jgroups.somewhere.MethodCall to send methods to ArrayList in a different node.

      MethodCall saves the ClassName, and the classNameArguments in order to perform the call.

      The problem is that AOPProxy.getClass().getName() is not a valid operation. You can't guarantee the proxy is always going to receive the same name.

      ObjectOutputStream will do this following check when doing outputStream.writeObject(someClass);

      if (proxy(theClass))
      {
       out.writeInterfaces(theProxy);
      }
      else
      {
       out.writeUTF(theClass.getClassName());
      }
      



      This way, when you readObject for the Class, if it's a proxy, the JDK (ObjectInputStream) would redefine the proxy for you.


      The problem is that the JDK don't know how to serialize AOPProxy classes.

      If you write an instance of AOpProxy, its serializable methods will substitute by proxies and do the correct serialization, but not on classNames.

      So, make sure you understand this:

      objectOut.writeObject(anInstanceOfTheProxy);// this is a correct operation
      objectOut.writeObject(anInstanceOfTheProxy.getClass()); // this is wrong!
      


      My suggestion would be to find a different way to send method calls to the other node, maybe extending jgroups.MethodCall and serializing an empty instance of the Proxy (without an interceptor).

        • 1. Re: JBCACHE-604 - Use of AOPPRoxy class name into streaming

          Clebert,

          Like i have mentioned in the email, from PojoCache side, I am not trying to serialize anInstanceOfTheProxy. Instead, I am trying to serializing the Class definition itself (so I can reconstruct the new instance from there). E.g., in terms of cache operation,

          put(fqn, key, anInstanceOfAopPoxy.getClass())

          Of course, we can argue that I may be able to get around this by simply passing the class name *String*. But that is a different story, IMO.

          • 2. Re: JBCACHE-604 - Use of AOPPRoxy class name into streaming
            clebert.suconic

            I know you are not serializing an instance of the proxy, and that's my whole point.

            How can you reconstruct the proxy by its class reference only?
            When you serialize that, you are serializing a name, and you will be trusting on the classLoader to give you the correct reference back.


            When you ask the classLoader the Proxy by its name, you can get a proxied class on a different class.

            You should improve your logic somehow, in such way you never do this:

            outObject.writeObject(anInstanceOfAProxy.getClass());
            or
            outObject.writeUTFanInstanceOfAProxy.getClass().getName());


            The JDK don't know how to handle AOPProxies.

            I don't know how you are going to fix this. I just know this is an invalid (semanticaly) operation, and I wanted to let you know that.



            If you want to discuss options, this is what I think:

            I - Serialize an instance of the proxy, since the instance can serialize itself correctly.
            II - Put the proxy definition in a wrapper class that will know how to recreate the proxy.
            III - Send proxy.getSuperClass() instead, and recreate the proxy from there.

            Well.. I don't konw much about POJOCache, so I don't know what's the best approach for you.

            But definetly:

            put(fqn, key, anInstanceOfAopPoxy.getClass()) ;

            can lead you in an error.


            You just need to have one of the JVMs creating an AOP proxy before the other. specially now Hibernate is also using AOPProxies, this is not so difficult to happen.

            • 3. Re: JBCACHE-604 - Use of AOPPRoxy class name into streaming
              clebert.suconic

              If you still think I'm wrong, let me translate to you what will happen on java.io.ObjectOUtputStream and INputSTream:


              objectOutputStream.writeObject(aopProxy.getClass());

              This is the same thing as:
              output.writeUTF(theObjectClass.getName());


              Class proxyClass = (Class)objectInputStream.readObject()

              This is the same thing as:
              String className = input.readUTF();
              Class proxyClass = theClassLoader.loadClass(className);



              So, this is why I'm picking up on the fact you are trusting the classLoader to give you the correct proxy reference.

              • 4. Re: JBCACHE-604 - Use of AOPPRoxy class name into streaming
                clebert.suconic

                Just to complete my point:

                if you were saving java.lang.Proxy.getClass(), the history would be completely different.

                This is because the JDK (ObjectOUtputSTream) has a special persister:

                if (Proxy.isProxy(theClass))
                {
                //// save the interfaces for later reconstructions
                }


                ont the read.

                Class [] interfaces = readTheInterfaces.
                Proxy.buildProxy(interfaces);


                The JDK don't know how to save AOPPRoxy classes.

                • 5. Re: JBCACHE-604 - Use of AOPPRoxy class name into streaming

                  Got it. Since I am only sending the Class object to the remote node (for it to reconstruct the no-arg isntance), I can do like your suggestion of proxy.getSuperClass() instead.

                  Thanks a lot!

                  • 6. Re: JBCACHE-604 - Use of AOPPRoxy class name into streaming
                    galder.zamarreno

                    Could this serialisation be part of the EnhancedTreeCacheMarshaller? We're already improving the way the MethodCalls and other objects are serialised using EnhancedTreeCacheMarshaller.

                    • 7. Re: JBCACHE-604 - Use of AOPPRoxy class name into streaming

                      No, it should not since it is PojoCache specific. I have resolved this issue.