@@ -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> | |||
@@ -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. | |||
*/ |
@@ -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(); } | |||
} | |||
} |