]> source.dussan.org Git - javassist.git/commitdiff
fixes a bug of ProxyFactory. It could not deal with default methods declared in...
authorchibash <chiba@javassist.org>
Sat, 30 Jul 2016 09:47:59 +0000 (18:47 +0900)
committerchibash <chiba@javassist.org>
Sat, 30 Jul 2016 09:47:59 +0000 (18:47 +0900)
src/main/javassist/util/proxy/ProxyFactory.java
src/test/test/javassist/proxy/ProxySimpleTest.java

index 26c5c6c9290e40ddccc9291f6a91891cf9eea0e7..a85e8de029f872b06daccc13fabc56aac2fe75da 100644 (file)
@@ -1230,7 +1230,7 @@ public class ProxyFactory {
         return minfo;
     }
 
-    private static MethodInfo makeDelegator(Method meth, String desc,
+    private MethodInfo makeDelegator(Method meth, String desc,
                 ConstPool cp, Class declClass, String delegatorName) {
         MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
         delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC
@@ -1243,7 +1243,8 @@ public class ProxyFactory {
         Bytecode code = new Bytecode(cp, 0, 0);
         code.addAload(0);
         int s = addLoadParameters(code, meth.getParameterTypes(), 1);
-        code.addInvokespecial(declClass.isInterface(), cp.addClassInfo(declClass.getName()),
+        Class targetClass = invokespecialTarget(declClass);
+        code.addInvokespecial(targetClass.isInterface(), cp.addClassInfo(targetClass.getName()),
                               meth.getName(), desc);
         addReturn(code, meth.getReturnType());
         code.setMaxLocals(++s);
@@ -1251,6 +1252,20 @@ public class ProxyFactory {
         return delegator;
     }
 
+    /* Suppose that the receiver type is S, the invoked method
+     * is declared in T, and U is the immediate super class of S
+     * (or its interface).  If S <: U <: T (S <: T reads "S extends T"), 
+     * the target type of invokespecial has to be not T but U.
+     */
+    private Class invokespecialTarget(Class declClass) {
+        if (declClass.isInterface())
+            for (Class i: interfaces)
+                if (declClass.isAssignableFrom(i))
+                    return i;
+
+        return superClass;
+    }
+
     /**
      * @param delegatorName     null if the original method is abstract.
      */
index f37e7b8c76fd56c1f9a69667aebe457509fa7ff4..1f06e42516afc37ae792f639b03e99707c00e12b 100644 (file)
@@ -140,4 +140,63 @@ public class ProxySimpleTest extends TestCase {
         public String extended() { return "ext"; }
         public String base2() { return super.base2() + "ext2"; }
     }
+
+    String valueDefaultMethods = "";
+
+    public void testDefaultMethods() throws Exception {
+        valueDefaultMethods = "";
+        ProxyFactory f = new ProxyFactory();
+        f.writeDirectory = "./proxy";
+        f.setSuperclass(Default3.class);
+        Class c = f.createClass();
+        MethodHandler mi = new MethodHandler() {
+            public Object invoke(Object self, Method m, Method proceed,
+                                 Object[] args) throws Throwable {
+                valueDefaultMethods += "1";
+                return proceed.invoke(self, args);  // execute the original method.
+            }
+        };
+        Default3 foo = (Default3)c.newInstance();
+        ((Proxy)foo).setHandler(mi);
+        foo.foo();
+        foo.bar();
+        assertEquals("11", valueDefaultMethods);   
+    }
+
+    public void testDefaultMethods2() throws Exception {
+        valueDefaultMethods = "";
+        ProxyFactory f = new ProxyFactory();
+        f.writeDirectory = "./proxy";
+        f.setInterfaces(new Class[] { Default2.class });
+        Class c = f.createClass();
+        MethodHandler mi = new MethodHandler() {
+            public Object invoke(Object self, Method m, Method proceed,
+                                 Object[] args) throws Throwable {
+                valueDefaultMethods += "1";
+                return proceed.invoke(self, args);  // execute the original method.
+            }
+        };
+        Default2 foo = (Default2)c.newInstance();
+        ((Proxy)foo).setHandler(mi);
+        foo.foo();
+        foo.bar();
+        assertEquals("11", valueDefaultMethods);   
+    }
+
+    public static interface Default1 {
+        default int foo() { return 0; }
+        default int baz() { return 2; }
+    }
+
+    public static interface Default2 extends Default1 {
+        default int bar() { return 1; }
+    }
+
+    public static class Default3 implements Default2 {
+        public int foo() { return Default2.super.foo(); }
+    }
+    
+    public static class Default4 extends Default3 {
+        public int baz() { return super.baz(); }
+    }
 }