]> source.dussan.org Git - javassist.git/commitdiff
fixed JASSIST-163. Eager initialization has been implemented.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 25 Oct 2012 16:38:40 +0000 (16:38 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Thu, 25 Oct 2012 16:38:40 +0000 (16:38 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@676 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

javassist.jar
src/main/javassist/util/proxy/MethodHandler.java
src/main/javassist/util/proxy/ProxyFactory.java
src/main/javassist/util/proxy/RuntimeSupport.java
src/test/javassist/JvstTest.java
src/test/javassist/proxyfactory/ProxyFactoryTest.java
src/test/test/javassist/proxy/ProxySimpleTest.java

index 87393d38453b9dc977ec832f6d9e3943b6fc073f..6cd27e1cfd46781f4fd5e9e0d9c3edfcaabd72a2 100644 (file)
Binary files a/javassist.jar and b/javassist.jar differ
index 9145895ae865b53f74f36915263760266c4a5880..2cd8fb165d4e68fd859d4fe187def0ca416c5b1f 100644 (file)
@@ -22,7 +22,7 @@ import java.lang.reflect.Method;
  * The interface implemented by the invocation handler of a proxy
  * instance.
  *
- * @see ProxyFactory#setHandler(MethodHandler)
+ * @see Proxy#setHandler(MethodHandler)
  */
 public interface MethodHandler {
     /**
@@ -33,7 +33,7 @@ public interface MethodHandler {
      * @param thisMethod    the overridden method declared in the super
      *                      class or interface.
      * @param proceed       the forwarder method for invoking the overridden 
-     *                      method.  It is null if the overridden mehtod is
+     *                      method.  It is null if the overridden method is
      *                      abstract or declared in the interface.
      * @param args          an array of objects containing the values of
      *                      the arguments passed in the method invocation
index 9bce51fafca7ab6cb9eb8b07f2960456ee4a5994..957ba8f1f13d24230caf19243820880e6a3b342e 100644 (file)
@@ -27,6 +27,7 @@ import java.util.*;
 import java.lang.ref.WeakReference;
 
 import javassist.CannotCompileException;
+import javassist.NotFoundException;
 import javassist.bytecode.*;
 
 /*
@@ -204,7 +205,7 @@ public class ProxyFactory {
 
     private static final String SERIAL_VERSION_UID_FIELD = "serialVersionUID";
     private static final String SERIAL_VERSION_UID_TYPE = "J";
-    private static final int SERIAL_VERSION_UID_VALUE = -1;
+    private static final long SERIAL_VERSION_UID_VALUE = -1L;
 
     /**
      * If true, a generated proxy class is cached and it will be reused
@@ -736,8 +737,10 @@ public class ProxyFactory {
         // HashMap allMethods = getMethods(superClass, interfaces);
         // int size = allMethods.size();
         makeConstructors(classname, cf, pool, classname);
-        int s = overrideMethods(cf, pool, classname);
-        addMethodsHolder(cf, pool, classname, s);
+
+        ArrayList forwarders = new ArrayList();
+        int s = overrideMethods(cf, pool, classname, forwarders);
+        addClassInitializer(cf, pool, classname, s, forwarders);
         addSetter(classname, cf, pool);
         if (!hasGetHandler)
             addGetter(classname, cf, pool);
@@ -875,8 +878,8 @@ public class ProxyFactory {
         cf.setInterfaces(list);
     }
 
-    private static void addMethodsHolder(ClassFile cf, ConstPool cp,
-                                         String classname, int size)
+    private static void addClassInitializer(ClassFile cf, ConstPool cp,
+                                    String classname, int size, ArrayList forwarders)
         throws CannotCompileException
     {
         FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);
@@ -884,18 +887,61 @@ public class ProxyFactory {
         cf.addField(finfo);
         MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
         minfo.setAccessFlags(AccessFlag.STATIC);
-        Bytecode code = new Bytecode(cp, 0, 0);
+        setThrows(minfo, cp, new Class[] { ClassNotFoundException.class });
+
+        Bytecode code = new Bytecode(cp, 0, 2);
         code.addIconst(size * 2);
         code.addAnewarray("java.lang.reflect.Method");
+        final int varArray = 0;
+        code.addAstore(varArray);
+
+        // forName() must be called here.  Otherwise, the class might be
+        // invisible.
+        code.addLdc(classname);
+        code.addInvokestatic("java.lang.Class",
+                "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
+        final int varClass = 1;
+        code.addAstore(varClass);
+
+        Iterator it = forwarders.iterator();
+        while (it.hasNext()) {
+            Find2MethodsArgs args = (Find2MethodsArgs)it.next();
+            callFind2Methods(code, args.methodName, args.delegatorName,
+                             args.origIndex, args.descriptor, varClass, varArray);
+        }
+
+        code.addAload(varArray);
         code.addPutstatic(classname, HOLDER, HOLDER_TYPE);
-        // also need to set serial version uid
-        code.addLconst(-1L);
+
+        code.addLconst(SERIAL_VERSION_UID_VALUE);
         code.addPutstatic(classname, SERIAL_VERSION_UID_FIELD, SERIAL_VERSION_UID_TYPE);
         code.addOpcode(Bytecode.RETURN);
         minfo.setCodeAttribute(code.toCodeAttribute());
         cf.addMethod(minfo);
     }
 
+    /**
+     * @param thisMethod        might be null.
+     */
+    private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod,
+                                         int index, String desc, int classVar, int arrayVar) {
+        String findClass = RuntimeSupport.class.getName();
+        String findDesc
+            = "(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V";
+
+        code.addAload(classVar);
+        code.addLdc(superMethod);
+        if (thisMethod == null)
+            code.addOpcode(Opcode.ACONST_NULL);
+        else
+            code.addLdc(thisMethod);
+
+        code.addIconst(index);
+        code.addLdc(desc);
+        code.addAload(arrayVar);
+        code.addInvokestatic(findClass, "find2Methods", findDesc);
+    }
+
     private static void addSetter(String classname, ClassFile cf, ConstPool cp)
         throws CannotCompileException
     {
@@ -925,7 +971,7 @@ public class ProxyFactory {
         cf.addMethod(minfo);
     }
 
-    private int overrideMethods(ClassFile cf, ConstPool cp, String className)
+    private int overrideMethods(ClassFile cf, ConstPool cp, String className, ArrayList forwarders)
         throws CannotCompileException
     {
         String prefix = makeUniqueName("_d", signatureMethods);
@@ -938,7 +984,7 @@ public class ProxyFactory {
             int mod = meth.getModifiers();
             if (testBit(signature, index)) {
                 override(className, meth, prefix, index,
-                         keyToDesc(key, meth), cf, cp);
+                         keyToDesc(key, meth), cf, cp, forwarders);
             }
             index++;
         }
@@ -947,7 +993,7 @@ public class ProxyFactory {
     }
 
     private void override(String thisClassname, Method meth, String prefix,
-                          int index, String desc, ClassFile cf, ConstPool cp)
+                          int index, String desc, ClassFile cf, ConstPool cp, ArrayList forwarders)
         throws CannotCompileException
     {
         Class declClass = meth.getDeclaringClass();
@@ -964,7 +1010,7 @@ public class ProxyFactory {
 
         MethodInfo forwarder
             = makeForwarder(thisClassname, meth, desc, cp, declClass,
-                            delegatorName, index);
+                            delegatorName, index, forwarders);
         cf.addMethod(forwarder);
     }
 
@@ -1154,7 +1200,8 @@ public class ProxyFactory {
      */
     private static MethodInfo makeForwarder(String thisClassName,
                     Method meth, String desc, ConstPool cp,
-                    Class declClass, String delegatorName, int index) {
+                    Class declClass, String delegatorName, int index,
+                    ArrayList forwarders) {
         MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
         forwarder.setAccessFlags(Modifier.FINAL
                     | (meth.getModifiers() & ~(Modifier.ABSTRACT
@@ -1164,13 +1211,14 @@ public class ProxyFactory {
         int args = Descriptor.paramSize(desc);
         Bytecode code = new Bytecode(cp, 0, args + 2);
         /*
-         * if (methods[index * 2] == null) {
+         * static {
          *   methods[index * 2]
          *     = RuntimeSupport.findSuperMethod(this, <overridden name>, <desc>);
          *   methods[index * 2 + 1]
          *     = RuntimeSupport.findMethod(this, <delegator name>, <desc>);
          *     or = null // the original method is abstract.
          * }
+         *     :
          * return ($r)handler.invoke(this, methods[index * 2],
          *                methods[index * 2 + 1], $args);
          */
@@ -1180,7 +1228,7 @@ public class ProxyFactory {
         code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);
         code.addAstore(arrayVar);
 
-        callFind2Methods(code, meth.getName(), delegatorName, origIndex, desc, arrayVar);
+        forwarders.add(new Find2MethodsArgs(meth.getName(), delegatorName, desc, origIndex));
 
         code.addAload(0);
         code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
@@ -1207,6 +1255,18 @@ public class ProxyFactory {
         return forwarder;
     }
 
+    static class Find2MethodsArgs {
+        String methodName, delegatorName, descriptor;
+        int origIndex;
+
+        Find2MethodsArgs(String mname, String dname, String desc, int index) {
+            methodName = mname;
+            delegatorName = dname;
+            descriptor = desc;
+            origIndex = index;
+        }
+    }
+
     private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {
         Class[] exceptions = orig.getExceptionTypes();
         setThrows(minfo, cp, exceptions);
@@ -1313,28 +1373,6 @@ public class ProxyFactory {
         return regno + FactoryHelper.dataSize[index];
     }
 
-    /**
-     * @param thisMethod        might be null.
-     */
-    private static void callFind2Methods(Bytecode code, String superMethod, String thisMethod,
-                                         int index, String desc, int arrayVar) {
-        String findClass = RuntimeSupport.class.getName();
-        String findDesc
-            = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;[Ljava/lang/reflect/Method;)V";
-
-        code.addAload(0);
-        code.addLdc(superMethod);
-        if (thisMethod == null)
-            code.addOpcode(Opcode.ACONST_NULL);
-        else
-            code.addLdc(thisMethod);
-
-        code.addIconst(index);
-        code.addLdc(desc);
-        code.addAload(arrayVar);
-        code.addInvokestatic(findClass, "find2Methods", findDesc);
-    }
-
     private static void addUnwrapper(Bytecode code, Class type) {
         if (type.isPrimitive()) {
             if (type == Void.TYPE)
index 48cacecdd60c9a5bde1a709cf89a4e2989194ef3..4c5d89961213d8a5177e072730fd5fab5f272988 100644 (file)
@@ -46,24 +46,13 @@ public class RuntimeSupport {
      * @throws RuntimeException     if the methods are not found.
      * @see javassist.util.proxy.ProxyFactory
      */
-    public static void find2Methods(Object self, String superMethod,
+    public static void find2Methods(Class clazz, String superMethod,
                                     String thisMethod, int index,
                                     String desc, java.lang.reflect.Method[] methods)
     {
-        /* Once methods[index] and methods[index + 1] are set to non-null, 
-         * then their values never change.
-         */
-        if (methods[index] == null || methods[index + 1] == null) {
-            Method m1 = thisMethod == null ? null
-                                           : findMethod(self, thisMethod, desc);
-            Method m0 = findSuperMethod(self, superMethod, desc);
-            synchronized (methods) {
-                if (methods[index] == null) {
-                    methods[index + 1] = m1;
-                    methods[index] = m0;
-                }
-            }
-        }
+        methods[index + 1] = thisMethod == null ? null
+                                                : findMethod(clazz, thisMethod, desc);
+        methods[index] = findSuperMethod(clazz, superMethod, desc);
     }
 
     /**
@@ -72,10 +61,10 @@ public class RuntimeSupport {
      *
      * @throws RuntimeException     if the method is not found.
      */
-    public static Method findMethod(Object self, String name, String desc) {
-        Method m = findMethod2(self.getClass(), name, desc);
+    public static Method findMethod(Class clazz, String name, String desc) {
+        Method m = findMethod2(clazz, name, desc);
         if (m == null)
-            error(self, name, desc);
+            error(clazz, name, desc);
 
         return m;
     }
@@ -86,21 +75,20 @@ public class RuntimeSupport {
      *
      * @throws RuntimeException     if the method is not found.
      */
-    public static Method findSuperMethod(Object self, String name, String desc) {
-        Class clazz = self.getClass();
+    public static Method findSuperMethod(Class clazz, String name, String desc) {
         Method m = findSuperMethod2(clazz.getSuperclass(), name, desc);
         if (m == null)
             m = searchInterfaces(clazz, name, desc);
 
         if (m == null)
-            error(self, name, desc);
+            error(clazz, name, desc);
 
         return m;
     }
 
-    private static void error(Object self, String name, String desc) {
+    private static void error(Class clazz, String name, String desc) {
         throw new RuntimeException("not found " + name + ":" + desc
-                + " in " + self.getClass().getName());
+                + " in " + clazz.getName());
     }
 
     private static Method findSuperMethod2(Class clazz, String name, String desc) {
index 4e22dbc16eb77132a892a191fa9886d88ba3b8b6..596d62e20a7c9f253cf856d66193443346c3cbab 100644 (file)
@@ -1116,14 +1116,14 @@ public class JvstTest extends JvstTestRoot {
         suite.addTestSuite(javassist.bytecode.InsertGap0.class);
         suite.addTestSuite(javassist.tools.reflect.LoaderTest.class);
         suite.addTestSuite(testproxy.ProxyTester.class);
-        // suite.addTestSuite(testproxy.ProxyFactoryPerformanceTest.class);
+        suite.addTestSuite(testproxy.ProxyFactoryPerformanceTest.class); // remove?
         suite.addTestSuite(javassist.proxyfactory.ProxyFactoryTest.class);
         suite.addTestSuite(javassist.proxyfactory.Tester.class);
         suite.addTestSuite(test.javassist.proxy.ProxySerializationTest.class);
         suite.addTestSuite(test.javassist.convert.ArrayAccessReplaceTest.class);
         suite.addTestSuite(test.javassist.proxy.JASSIST113RegressionTest.class);
         suite.addTestSuite(test.javassist.proxy.JBPAPP9257Test.class);
-        //suite.addTestSuite(test.javassist.proxy.ProxyCacheGCTest.class);
+        suite.addTestSuite(test.javassist.proxy.ProxyCacheGCTest.class);  // remvoe?
         suite.addTestSuite(test.javassist.proxy.ProxyFactoryCompatibilityTest.class);
         suite.addTestSuite(test.javassist.proxy.ProxySerializationTest.class);
         suite.addTestSuite(test.javassist.proxy.ProxySimpleTest.class);
index 7224eb506fd24d3f5d298388ba12d3b9c35d3a06..232a0165b42268fd4f450a31ae3172bfe41126f9 100644 (file)
@@ -12,8 +12,6 @@ import java.lang.reflect.Method;
  * <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
  */
 public class ProxyFactoryTest extends TestCase {
-
-
     public void testMethodHandlers() throws Exception {
         ProxyFactory fact = new ProxyFactory();
         fact.setSuperclass(MyCls.class);
index f74fce45abf00e79c3cb3f3ded2c3c2c5a6dcac8..cab62397b40b0715c6f27200a9007f4ec5600c1d 100644 (file)
@@ -9,9 +9,47 @@ import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.lang.reflect.Method;
 
+import javassist.util.proxy.MethodFilter;
+import javassist.util.proxy.MethodHandler;
+import javassist.util.proxy.Proxy;
 import javassist.util.proxy.ProxyFactory;
 
 public class ProxySimpleTest extends TestCase {
+
+    String testResult;
+
+    public void testProxyFactory() throws Exception {
+        ProxyFactory f = new ProxyFactory();
+        f.writeDirectory = "./proxy";
+        f.setSuperclass(Foo.class);
+        f.setFilter(new MethodFilter() {
+            public boolean isHandled(Method m) {
+                return m.getName().startsWith("f");
+            }
+        });
+        Class c = f.createClass();
+        MethodHandler mi = new MethodHandler() {
+            public Object invoke(Object self, Method m, Method proceed,
+                                 Object[] args) throws Throwable {
+                testResult += args[0].toString();
+                return proceed.invoke(self, args);  // execute the original method.
+            }
+        };
+        Foo foo = (Foo)c.newInstance();
+        ((Proxy)foo).setHandler(mi);
+        testResult = "";
+        foo.foo(1);
+        foo.foo2(2);
+        foo.bar(3);
+        assertEquals("12", testResult);
+    }
+
+    public static class Foo {
+        public int foo(int i) { return i + 1; }
+        public int foo2(int i) { return i + 2; }
+        public int bar(int i) { return i + 1; }
+    }
+
     public void testReadWrite() throws Exception {
         final String fileName = "read-write.bin";
         ProxyFactory.ClassLoaderProvider cp = ProxyFactory.classLoaderProvider;