aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchibash <chiba@javassist.org>2016-07-30 18:47:59 +0900
committerchibash <chiba@javassist.org>2016-07-30 21:12:17 +0900
commitd5677e4a3ac426e7c39f478c75b08b6c1c4674fc (patch)
tree2d59131579f47b0e3f891c0ff95f48d4977b0dba
parent13c7057570305ca3b6d3890ec3f509f487c6973a (diff)
downloadjavassist-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.html3
-rw-r--r--src/main/javassist/util/proxy/ProxyFactory.java19
-rw-r--r--src/test/test/javassist/proxy/ProxySimpleTest.java59
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(); }
+ }
}