Browse Source

fixes a bug of ProxyFactory. It could not deal with default methods declared in an interface. https://github.com/jboss-javassist/javassist/issues/45

tags/rel_3_21_0-java9-ea
chibash 7 years ago
parent
commit
d5677e4a3a

+ 2
- 1
Readme.html View File

<li>JIRA JASSIST-244, 245, 248, 250, 255, 256, 259, 262. <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. <li><code>javassist.tools.Callback</code> was modified to be Java 1.4 compatible.
The parameter type of <code>Callback#result()</code> was changed. 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> </ul>
</p> </p>



+ 17
- 2
src/main/javassist/util/proxy/ProxyFactory.java View File

return minfo; return minfo;
} }


private static MethodInfo makeDelegator(Method meth, String desc,
private MethodInfo makeDelegator(Method meth, String desc,
ConstPool cp, Class declClass, String delegatorName) { ConstPool cp, Class declClass, String delegatorName) {
MethodInfo delegator = new MethodInfo(cp, delegatorName, desc); MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC
Bytecode code = new Bytecode(cp, 0, 0); Bytecode code = new Bytecode(cp, 0, 0);
code.addAload(0); code.addAload(0);
int s = addLoadParameters(code, meth.getParameterTypes(), 1); 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); meth.getName(), desc);
addReturn(code, meth.getReturnType()); addReturn(code, meth.getReturnType());
code.setMaxLocals(++s); code.setMaxLocals(++s);
return delegator; 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. * @param delegatorName null if the original method is abstract.
*/ */

+ 59
- 0
src/test/test/javassist/proxy/ProxySimpleTest.java View File

public String extended() { return "ext"; } public String extended() { return "ext"; }
public String base2() { return super.base2() + "ext2"; } 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(); }
}
} }

Loading…
Cancel
Save