Pass the correct Method instance to the InvocationHandlers

We should pass the method of the original interface to the
InvocationHandler, not the method of the interface.

That way, proxy instances of annotations will have easy access to
the default values.

This happens to be compatible with the way Oracle Java does it, too.

To accomplish our goal, we keep a global map between proxy classes and
Method references and assign the appropriate list to a field of the
Proxy subclass. This means that we now have to call the super-class
constructor in the generated constructor (which is the correct thing to
do anyway... ;-)).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin 2013-11-26 15:03:53 -06:00
parent 6f5bcb00b9
commit 0a179355f4

View File

@ -29,6 +29,8 @@ import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.HashSet;
import java.io.OutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -37,6 +39,13 @@ public class Proxy {
private static int nextNumber;
protected InvocationHandler h;
protected final static Map<Class, Method[]> methodRefsMap =
new HashMap<Class, Method[]>();
protected final Method[] methodRefs;
public Proxy() {
methodRefs = methodRefsMap.get(getClass());
}
public static Class getProxyClass(ClassLoader loader,
Class ... interfaces)
@ -90,15 +99,14 @@ public class Proxy {
write1(out, aload_0);
write1(out, ldc_w);
write2(out, ConstantPool.addClass(pool, className) + 1);
write1(out, aload_0);
write1(out, getfield);
write2(out, ConstantPool.addFieldRef
(pool, className,
"methodRefs", "[Ljava/lang/reflect/Method;") + 1);
write1(out, ldc_w);
write2(out, ConstantPool.addInteger(pool, index) + 1);
write1(out, invokestatic);
write2(out, ConstantPool.addMethodRef
(pool, "avian/Classes",
"makeMethod", "(Ljava/lang/Class;I)Ljava/lang/reflect/Method;")
+ 1);
write1(out, aaload);
write1(out, ldc_w);
write2(out, ConstantPool.addInteger(pool, parameterCount) + 1);
@ -324,7 +332,13 @@ public class Proxy {
ByteArrayOutputStream out = new ByteArrayOutputStream();
write2(out, 2); // max stack
write2(out, 2); // max locals
write4(out, 6); // length
write4(out, 10); // length
write1(out, aload_0);
write1(out, invokespecial);
write2(out, ConstantPool.addMethodRef
(pool, "java/lang/reflect/Proxy",
"<init>", "()V") + 1);
write1(out, aload_0);
write1(out, aload_1);
@ -353,47 +367,48 @@ public class Proxy {
(pool, interfaces[i].getName().replace('.', '/'));
}
Map<String,avian.VMMethod> virtualMap = new HashMap();
Set<String> specs = new HashSet<String>();
List<MethodData> methodTable = new ArrayList<MethodData>();
List<Method> refs = new ArrayList<Method>();
for (Class c: interfaces) {
avian.VMMethod[] ivtable = SystemClassLoader.vmClass(c).virtualTable;
if (ivtable != null) {
for (avian.VMMethod m: ivtable) {
virtualMap.put
(Classes.toString(m.name) + Classes.toString(m.spec), m);
String spec = Classes.toString(m.name) + Classes.toString(m.spec);
if (specs.contains(spec)) {
continue;
}
methodTable.add(new MethodData
(Modifier.PUBLIC,
ConstantPool.addUtf8(pool, Classes.toString(m.name)),
ConstantPool.addUtf8(pool, Classes.toString(m.spec)),
makeInvokeCode(pool, name, m.spec, m.parameterCount,
m.parameterFootprint, methodTable.size())));
refs.add(new Method(m));
}
}
}
MethodData[] methodTable = new MethodData[virtualMap.size() + 1];
{ int i = 0;
for (avian.VMMethod m: virtualMap.values()) {
methodTable[i] = new MethodData
(Modifier.PUBLIC,
ConstantPool.addUtf8(pool, Classes.toString(m.name)),
ConstantPool.addUtf8(pool, Classes.toString(m.spec)),
makeInvokeCode(pool, name, m.spec, m.parameterCount,
m.parameterFootprint, i));
++ i;
}
methodTable[i++] = new MethodData
(Modifier.PUBLIC,
ConstantPool.addUtf8(pool, "<init>"),
ConstantPool.addUtf8
(pool, "(Ljava/lang/reflect/InvocationHandler;)V"),
makeConstructorCode(pool));
}
methodTable.add(new MethodData
(Modifier.PUBLIC,
ConstantPool.addUtf8(pool, "<init>"),
ConstantPool.addUtf8
(pool, "(Ljava/lang/reflect/InvocationHandler;)V"),
makeConstructorCode(pool)));
int nameIndex = ConstantPool.addClass(pool, name);
int superIndex = ConstantPool.addClass(pool, "java/lang/reflect/Proxy");
ByteArrayOutputStream out = new ByteArrayOutputStream();
Assembler.writeClass
(out, pool, nameIndex, superIndex, interfaceIndexes, methodTable);
(out, pool, nameIndex, superIndex, interfaceIndexes,
methodTable.toArray(new MethodData[methodTable.size()]));
byte[] classData = out.toByteArray();
return avian.SystemClassLoader.getClass
Class result = avian.SystemClassLoader.getClass
(avian.Classes.defineVMClass(loader, classData, 0, classData.length));
methodRefsMap.put(result, refs.toArray(new Method[refs.size()]));
return result;
}
public static Object newProxyInstance(ClassLoader loader,