diff options
author | chibash <chiba@javassist.org> | 2016-07-30 18:47:59 +0900 |
---|---|---|
committer | chibash <chiba@javassist.org> | 2016-07-30 21:12:17 +0900 |
commit | d5677e4a3ac426e7c39f478c75b08b6c1c4674fc (patch) | |
tree | 2d59131579f47b0e3f891c0ff95f48d4977b0dba | |
parent | 13c7057570305ca3b6d3890ec3f509f487c6973a (diff) | |
download | javassist-d5677e4a3ac426e7c39f478c75b08b6c1c4674fc.tar.gz javassist-d5677e4a3ac426e7c39f478c75b08b6c1c4674fc.zip |
fixes a bug of ProxyFactory. It could not deal with default methods declared in an interface. https://github.com/jboss-javassist/javassist/issues/45
-rw-r--r-- | Readme.html | 3 | ||||
-rw-r--r-- | src/main/javassist/util/proxy/ProxyFactory.java | 19 | ||||
-rw-r--r-- | src/test/test/javassist/proxy/ProxySimpleTest.java | 59 |
3 files changed, 78 insertions, 3 deletions
diff --git a/Readme.html b/Readme.html index 7e16e186..c80abd21 100644 --- a/Readme.html +++ b/Readme.html @@ -286,7 +286,8 @@ see javassist.Dump. <li>JIRA JASSIST-244, 245, 248, 250, 255, 256, 259, 262. <li><code>javassist.tools.Callback</code> was modified to be Java 1.4 compatible. The parameter type of <code>Callback#result()</code> was changed. -<li>The algorithm for generating a stack-map table was modified to fix github issue #83. +<li>The algorithm for generating a stack-map table was modified to fix github issue #83. +<li>A bug of ProxyFactory related to default methods was fixed. It is github issue #45. </ul> </p> diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java index 26c5c6c9..a85e8de0 100644 --- a/src/main/javassist/util/proxy/ProxyFactory.java +++ b/src/main/javassist/util/proxy/ProxyFactory.java @@ -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. */ diff --git a/src/test/test/javassist/proxy/ProxySimpleTest.java b/src/test/test/javassist/proxy/ProxySimpleTest.java index f37e7b8c..289895cc 100644 --- a/src/test/test/javassist/proxy/ProxySimpleTest.java +++ b/src/test/test/javassist/proxy/ProxySimpleTest.java @@ -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(); } + } } |