mirror of
https://github.com/corda/corda.git
synced 2025-02-10 21:01:27 +00:00
Merge pull request #102 from dscho/proxy-annotations
This looks good to me, good work.
This commit is contained in:
commit
a2e1e1eec9
@ -21,11 +21,12 @@ public class AnnotationInvocationHandler implements InvocationHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Object invoke(Object proxy, Method method, Object[] arguments) {
|
public Object invoke(Object proxy, Method method, Object[] arguments) {
|
||||||
|
String name = method.getName();
|
||||||
for (int i = 2; i < data.length; i += 2) {
|
for (int i = 2; i < data.length; i += 2) {
|
||||||
if (method.getName().equals(data[i])) {
|
if (name.equals(data[i])) {
|
||||||
return data[i + 1];
|
return data[i + 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new IllegalArgumentException();
|
return method.getDefaultValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ public class Classes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case '@':
|
case '@':
|
||||||
return parseAnnotation(loader, pool, in);
|
return getAnnotation(loader, parseAnnotation(loader, pool, in));
|
||||||
|
|
||||||
case '[': {
|
case '[': {
|
||||||
Object[] array = new Object[read2(in)];
|
Object[] array = new Object[read2(in)];
|
||||||
@ -450,6 +450,25 @@ public class Classes {
|
|||||||
return (Annotation) a[0];
|
return (Annotation) a[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Object getAnnotationDefaultValue(ClassLoader loader,
|
||||||
|
MethodAddendum addendum) {
|
||||||
|
if (addendum == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
byte[] annotationDefault = (byte[]) addendum.annotationDefault;
|
||||||
|
if (annotationDefault == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return parseAnnotationValue(loader, addendum.pool,
|
||||||
|
new ByteArrayInputStream(annotationDefault));
|
||||||
|
} catch (IOException e) {
|
||||||
|
AssertionError error = new AssertionError();
|
||||||
|
error.initCause(e);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static native Method makeMethod(Class c, int slot);
|
public static native Method makeMethod(Class c, int slot);
|
||||||
|
|
||||||
private static native void acquireClassLock();
|
private static native void acquireClassLock();
|
||||||
|
@ -142,4 +142,9 @@ public class Method<T> extends AccessibleObject implements Member {
|
|||||||
public boolean isVarArgs() {
|
public boolean isVarArgs() {
|
||||||
return (getModifiers() & 0x80) != 0;
|
return (getModifiers() & 0x80) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Object getDefaultValue() {
|
||||||
|
ClassLoader loader = getDeclaringClass().getClassLoader();
|
||||||
|
return Classes.getAnnotationDefaultValue(loader, vmMethod.addendum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,8 @@ import java.util.List;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -37,6 +39,13 @@ public class Proxy {
|
|||||||
private static int nextNumber;
|
private static int nextNumber;
|
||||||
|
|
||||||
protected InvocationHandler h;
|
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,
|
public static Class getProxyClass(ClassLoader loader,
|
||||||
Class ... interfaces)
|
Class ... interfaces)
|
||||||
@ -90,15 +99,14 @@ public class Proxy {
|
|||||||
|
|
||||||
write1(out, aload_0);
|
write1(out, aload_0);
|
||||||
|
|
||||||
write1(out, ldc_w);
|
write1(out, aload_0);
|
||||||
write2(out, ConstantPool.addClass(pool, className) + 1);
|
write1(out, getfield);
|
||||||
|
write2(out, ConstantPool.addFieldRef
|
||||||
|
(pool, className,
|
||||||
|
"methodRefs", "[Ljava/lang/reflect/Method;") + 1);
|
||||||
write1(out, ldc_w);
|
write1(out, ldc_w);
|
||||||
write2(out, ConstantPool.addInteger(pool, index) + 1);
|
write2(out, ConstantPool.addInteger(pool, index) + 1);
|
||||||
write1(out, invokestatic);
|
write1(out, aaload);
|
||||||
write2(out, ConstantPool.addMethodRef
|
|
||||||
(pool, "avian/Classes",
|
|
||||||
"makeMethod", "(Ljava/lang/Class;I)Ljava/lang/reflect/Method;")
|
|
||||||
+ 1);
|
|
||||||
|
|
||||||
write1(out, ldc_w);
|
write1(out, ldc_w);
|
||||||
write2(out, ConstantPool.addInteger(pool, parameterCount) + 1);
|
write2(out, ConstantPool.addInteger(pool, parameterCount) + 1);
|
||||||
@ -324,7 +332,13 @@ public class Proxy {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
write2(out, 2); // max stack
|
write2(out, 2); // max stack
|
||||||
write2(out, 2); // max locals
|
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_0);
|
||||||
write1(out, aload_1);
|
write1(out, aload_1);
|
||||||
@ -353,47 +367,48 @@ public class Proxy {
|
|||||||
(pool, interfaces[i].getName().replace('.', '/'));
|
(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) {
|
for (Class c: interfaces) {
|
||||||
avian.VMMethod[] ivtable = SystemClassLoader.vmClass(c).virtualTable;
|
avian.VMMethod[] ivtable = SystemClassLoader.vmClass(c).virtualTable;
|
||||||
if (ivtable != null) {
|
if (ivtable != null) {
|
||||||
for (avian.VMMethod m: ivtable) {
|
for (avian.VMMethod m: ivtable) {
|
||||||
virtualMap.put
|
String spec = Classes.toString(m.name) + Classes.toString(m.spec);
|
||||||
(Classes.toString(m.name) + Classes.toString(m.spec), m);
|
if (specs.contains(spec)) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
methodTable.add(new MethodData
|
||||||
}
|
(Modifier.PUBLIC,
|
||||||
|
|
||||||
MethodData[] methodTable = new MethodData[virtualMap.size() + 1];
|
|
||||||
{ int i = 0;
|
|
||||||
for (avian.VMMethod m: virtualMap.values()) {
|
|
||||||
methodTable[i] = new MethodData
|
|
||||||
(0,
|
|
||||||
ConstantPool.addUtf8(pool, Classes.toString(m.name)),
|
ConstantPool.addUtf8(pool, Classes.toString(m.name)),
|
||||||
ConstantPool.addUtf8(pool, Classes.toString(m.spec)),
|
ConstantPool.addUtf8(pool, Classes.toString(m.spec)),
|
||||||
makeInvokeCode(pool, name, m.spec, m.parameterCount,
|
makeInvokeCode(pool, name, m.spec, m.parameterCount,
|
||||||
m.parameterFootprint, i));
|
m.parameterFootprint, methodTable.size())));
|
||||||
++ i;
|
refs.add(new Method(m));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
methodTable[i++] = new MethodData
|
methodTable.add(new MethodData
|
||||||
(Modifier.PUBLIC,
|
(Modifier.PUBLIC,
|
||||||
ConstantPool.addUtf8(pool, "<init>"),
|
ConstantPool.addUtf8(pool, "<init>"),
|
||||||
ConstantPool.addUtf8
|
ConstantPool.addUtf8
|
||||||
(pool, "(Ljava/lang/reflect/InvocationHandler;)V"),
|
(pool, "(Ljava/lang/reflect/InvocationHandler;)V"),
|
||||||
makeConstructorCode(pool));
|
makeConstructorCode(pool)));
|
||||||
}
|
|
||||||
|
|
||||||
int nameIndex = ConstantPool.addClass(pool, name);
|
int nameIndex = ConstantPool.addClass(pool, name);
|
||||||
int superIndex = ConstantPool.addClass(pool, "java/lang/reflect/Proxy");
|
int superIndex = ConstantPool.addClass(pool, "java/lang/reflect/Proxy");
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Assembler.writeClass
|
Assembler.writeClass
|
||||||
(out, pool, nameIndex, superIndex, interfaceIndexes, methodTable);
|
(out, pool, nameIndex, superIndex, interfaceIndexes,
|
||||||
|
methodTable.toArray(new MethodData[methodTable.size()]));
|
||||||
|
|
||||||
byte[] classData = out.toByteArray();
|
byte[] classData = out.toByteArray();
|
||||||
return avian.SystemClassLoader.getClass
|
Class result = avian.SystemClassLoader.getClass
|
||||||
(avian.Classes.defineVMClass(loader, classData, 0, classData.length));
|
(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,
|
public static Object newProxyInstance(ClassLoader loader,
|
||||||
|
2
makefile
2
makefile
@ -1567,7 +1567,7 @@ $(test-dep): $(test-sources) $(test-library)
|
|||||||
@mkdir -p $(test-build)
|
@mkdir -p $(test-build)
|
||||||
files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \
|
files="$(shell $(MAKE) -s --no-print-directory build=$(build) $(test-classes))"; \
|
||||||
if test -n "$${files}"; then \
|
if test -n "$${files}"; then \
|
||||||
$(javac) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \
|
$(javac) -classpath $(test-build) -d $(test-build) -bootclasspath $(boot-classpath) $${files}; \
|
||||||
fi
|
fi
|
||||||
$(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \
|
$(javac) -source 1.2 -target 1.1 -XDjsrlimit=0 -d $(test-build) \
|
||||||
-bootclasspath $(boot-classpath) test/Subroutine.java
|
-bootclasspath $(boot-classpath) test/Subroutine.java
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
|
||||||
import avian.testing.annotations.Color;
|
import avian.testing.annotations.Color;
|
||||||
import avian.testing.annotations.Test;
|
import avian.testing.annotations.Test;
|
||||||
|
import avian.testing.annotations.TestComplex;
|
||||||
import avian.testing.annotations.TestEnum;
|
import avian.testing.annotations.TestEnum;
|
||||||
import avian.testing.annotations.TestInteger;
|
import avian.testing.annotations.TestInteger;
|
||||||
|
|
||||||
@ -27,6 +30,8 @@ public class Annotations {
|
|||||||
Method noAnno = Annotations.class.getMethod("noAnnotation");
|
Method noAnno = Annotations.class.getMethod("noAnnotation");
|
||||||
expect(noAnno.getAnnotation(Test.class) == null);
|
expect(noAnno.getAnnotation(Test.class) == null);
|
||||||
expect(noAnno.getAnnotations().length == 0);
|
expect(noAnno.getAnnotations().length == 0);
|
||||||
|
testProxyDefaultValue();
|
||||||
|
testComplexAnnotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test("couscous")
|
@Test("couscous")
|
||||||
@ -39,4 +44,46 @@ public class Annotations {
|
|||||||
public static void noAnnotation() {
|
public static void noAnnotation() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void testProxyDefaultValue() {
|
||||||
|
ClassLoader loader = Annotations.class.getClassLoader();
|
||||||
|
InvocationHandler handler = new InvocationHandler() {
|
||||||
|
public Object invoke(Object proxy, Method method, Object... args) {
|
||||||
|
return method.getDefaultValue();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Test test = (Test)
|
||||||
|
Proxy.newProxyInstance(loader, new Class[] { Test.class }, handler);
|
||||||
|
expect("Hello, world!".equals(test.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface World {
|
||||||
|
@TestComplex(arrayValue = { @Test, @Test(value = "7/9") },
|
||||||
|
stringValue = "adjunct element", charValue = '7', doubleValue = 0.7778,
|
||||||
|
classValue = TestInteger.class)
|
||||||
|
int hello();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testComplexAnnotation(TestComplex annotation)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
expect(2 == annotation.arrayValue().length);
|
||||||
|
expect("Hello, world!".equals(annotation.arrayValue()[0].value()));
|
||||||
|
expect("7/9".equals(annotation.arrayValue()[1].value()));
|
||||||
|
expect("adjunct element".equals(annotation.stringValue()));
|
||||||
|
expect('7' == annotation.charValue());
|
||||||
|
expect(0.7778 == annotation.doubleValue());
|
||||||
|
expect(TestInteger.class == annotation.classValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void testComplexAnnotation() throws Exception {
|
||||||
|
ClassLoader loader = Annotations.class.getClassLoader();
|
||||||
|
TestComplex annotation = (TestComplex)
|
||||||
|
World.class.getMethod("hello").getAnnotation(TestComplex.class);
|
||||||
|
testComplexAnnotation(annotation);
|
||||||
|
Class clazz = Proxy.getProxyClass(loader, new Class[] { World.class });
|
||||||
|
annotation = (TestComplex)
|
||||||
|
clazz.getMethod("hello").getAnnotation(TestComplex.class);
|
||||||
|
expect(annotation == null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@ import java.lang.annotation.RetentionPolicy;
|
|||||||
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
public @interface Test {
|
public @interface Test {
|
||||||
public String value();
|
public String value() default "Hello, world!";
|
||||||
}
|
}
|
||||||
|
14
test/avian/testing/annotations/TestComplex.java
Normal file
14
test/avian/testing/annotations/TestComplex.java
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package avian.testing.annotations;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TestComplex {
|
||||||
|
public Test[] arrayValue();
|
||||||
|
public Class classValue();
|
||||||
|
public String stringValue();
|
||||||
|
public char charValue();
|
||||||
|
public double doubleValue();
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user