mirror of
https://github.com/corda/corda.git
synced 2025-01-06 13:08:46 +00:00
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:
parent
6f5bcb00b9
commit
0a179355f4
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user