support runtime-visible annotations and java.lang.reflect.Proxy

This commit is contained in:
Joel Dice
2009-09-18 18:01:54 -06:00
parent a2a33c259e
commit 7aa906d97b
23 changed files with 1278 additions and 169 deletions

View File

@ -10,14 +10,20 @@
package java.lang;
import avian.AnnotationInvocationHandler;
import avian.Pair;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.AnnotatedElement;
import java.lang.annotation.Annotation;
import java.io.InputStream;
import java.io.IOException;
@ -28,8 +34,11 @@ import java.security.ProtectionDomain;
import java.security.Permissions;
import java.security.AllPermission;
public final class Class <T> implements Type, GenericDeclaration {
public final class Class <T>
implements Type, GenericDeclaration, AnnotatedElement
{
private static final int PrimitiveFlag = 1 << 5;
private static final int LinkFlag = 1 << 8;
private short flags;
private short vmFlags;
@ -44,6 +53,7 @@ public final class Class <T> implements Type, GenericDeclaration {
private Method[] virtualTable;
private Field[] fieldTable;
private Method[] methodTable;
private Addendum addendum;
private Object staticTable;
private ClassLoader loader;
@ -139,6 +149,157 @@ public final class Class <T> implements Type, GenericDeclaration {
}
}
private static Class loadClass(ClassLoader loader,
byte[] nameBytes, int offset, int length)
{
String name = new String(nameBytes, offset, length, false);
try {
return loader.loadClass(name);
} catch (ClassNotFoundException e) {
NoClassDefFoundError error = new NoClassDefFoundError(name);
error.initCause(e);
throw error;
}
}
private static Object resolveAnnotationValue(ClassLoader loader,
Object raw)
{
if (raw instanceof Pair) {
Pair<byte[],byte[]> p = (Pair<byte[],byte[]>) raw;
return Enum.valueOf
(loadClass(loader, p.first, 1, p.first.length - 3),
new String(p.second, 0, p.second.length - 1, false));
} else if (raw instanceof byte[]) {
byte[] typeName = (byte[]) raw;
return loadClass(loader, typeName, 0, typeName.length - 1);
} else if (raw.getClass().isArray()) {
Object[] array = (Object[]) raw;
if (array.length > 0 && array[0] == null) {
resolveAnnotation(loader, array);
} else {
for (int i = 0; i < array.length; ++i) {
array[i] = resolveAnnotationValue(loader, array[i]);
}
}
}
return raw;
}
private static void resolveAnnotation(ClassLoader loader,
Object[] annotation)
{
byte[] typeName = (byte[]) annotation[1];
annotation[1] = loadClass(loader, typeName, 1, typeName.length - 3);
for (int i = 2; i < annotation.length; i += 2) {
byte[] name = (byte[]) annotation[i];
annotation[i] = new String(name, 0, name.length - 1, false).intern();
annotation[i + 1] = resolveAnnotationValue(loader, annotation[i + 1]);
}
}
private static void resolveAnnotationTable(ClassLoader loader,
Object[] table)
{
for (int i = 0; i < table.length; ++i) {
resolveAnnotation(loader, (Object[]) table[i]);
}
}
private static int resolveSpec(ClassLoader loader, byte[] spec, int start) {
int result;
int end;
switch (spec[start]) {
case 'L':
++ start;
end = start;
while (spec[end] != ';') ++ end;
result = end + 1;
break;
case '[':
end = start + 1;
while (spec[end] == '[') ++ end;
switch (spec[end]) {
case 'L':
++ end;
while (spec[end] != ';') ++ end;
++ end;
break;
default:
++ end;
}
result = end;
break;
default:
return start + 1;
}
loadClass(loader, spec, start, end - start);
return result;
}
private static native void acquireClassLock();
private static native void releaseClassLock();
void link(ClassLoader loader) {
acquireClassLock();
try {
if ((vmFlags & LinkFlag) == 0) {
if (super_ != null) {
super_.link(loader);
}
if (addendum != null && addendum.annotationTable != null) {
resolveAnnotationTable(loader, addendum.annotationTable);
}
if (interfaceTable != null) {
int stride = (isInterface() ? 1 : 2);
for (int i = 0; i < interfaceTable.length; i += stride) {
((Class) interfaceTable[i]).link(loader);
}
}
if (methodTable != null) {
for (int i = 0; i < methodTable.length; ++i) {
Method m = methodTable[i];
for (int j = 1; j < m.spec.length;) {
j = resolveSpec(loader, m.spec, j);
}
if (m.addendum != null && m.addendum.annotationTable != null) {
resolveAnnotationTable(loader, m.addendum.annotationTable);
}
}
}
if (fieldTable != null) {
for (int i = 0; i < fieldTable.length; ++i) {
Field f = fieldTable[i];
resolveSpec(loader, f.spec, 0);
if (f.addendum != null && f.addendum.annotationTable != null) {
resolveAnnotationTable(loader, f.addendum.annotationTable);
}
}
}
vmFlags |= LinkFlag;
}
} finally {
releaseClassLock();
}
}
public static Class forName(String name) throws ClassNotFoundException {
return forName
(name, true, Method.getCaller().getDeclaringClass().getClassLoader());
@ -161,8 +322,6 @@ public final class Class <T> implements Type, GenericDeclaration {
private static native Class primitiveClass(char name);
private native void link(ClassLoader loader);
private native void initialize();
public static Class forCanonicalName(String name) {
@ -479,9 +638,10 @@ public final class Class <T> implements Type, GenericDeclaration {
if (interfaceTable != null) {
link(loader);
Class[] array = new Class[interfaceTable.length / 2];
int stride = (isInterface() ? 1 : 2);
Class[] array = new Class[interfaceTable.length / stride];
for (int i = 0; i < array.length; ++i) {
array[i] = (Class) interfaceTable[i * 2];
array[i] = (Class) interfaceTable[i * stride];
}
return array;
} else {
@ -566,7 +726,7 @@ public final class Class <T> implements Type, GenericDeclaration {
}
public Object[] getSigners() {
return Static.signers.get(this);
return addendum == null ? null : addendum.signers;
}
public Package getPackage() {
@ -584,8 +744,76 @@ public final class Class <T> implements Type, GenericDeclaration {
}
}
public boolean isAnnotationPresent
(Class<? extends Annotation> class_)
{
return getAnnotation(class_) != null;
}
private Annotation getAnnotation(Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
(loader, new Class[] { (Class) a[1] },
new AnnotationInvocationHandler(a));
}
return (Annotation) a[0];
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
for (Class c = this; c != null; c = c.super_) {
if (c.addendum != null && c.addendum.annotationTable != null) {
link(c.loader);
Object[] table = c.addendum.annotationTable;
for (int i = 0; i < table.length; ++i) {
Object[] a = (Object[]) table[i];
if (a[1] == class_) {
return (T) c.getAnnotation(a);
}
}
}
}
return null;
}
public Annotation[] getDeclaredAnnotations() {
throw new UnsupportedOperationException();
if (addendum != null && addendum.annotationTable != null) {
link(loader);
Object[] table = addendum.annotationTable;
Annotation[] array = new Annotation[table.length];
for (int i = 0; i < table.length; ++i) {
array[i] = getAnnotation((Object[]) table[i]);
}
return array;
} else {
return new Annotation[0];
}
}
private int countAnnotations() {
int count = 0;
for (Class c = this; c != null; c = c.super_) {
if (c.addendum != null && c.addendum.annotationTable != null) {
count += c.addendum.annotationTable.length;
}
}
return count;
}
public Annotation[] getAnnotations() {
Annotation[] array = new Annotation[countMethods(true)];
int i = 0;
for (Class c = this; c != null; c = c.super_) {
if (c.addendum != null && c.addendum.annotationTable != null) {
Object[] table = c.addendum.annotationTable;
for (int j = 0; j < table.length; ++j) {
array[i++] = getAnnotation((Object[]) table[j]);
}
}
}
return array;
}
public boolean isEnum() {
@ -612,10 +840,6 @@ public final class Class <T> implements Type, GenericDeclaration {
throw new UnsupportedOperationException();
}
public <A extends Annotation> A getAnnotation(Class<A> c) {
throw new UnsupportedOperationException();
}
public ProtectionDomain getProtectionDomain() {
Permissions p = new Permissions();
p.add(new AllPermission());
@ -625,11 +849,15 @@ public final class Class <T> implements Type, GenericDeclaration {
// for GNU Classpath compatibility:
void setSigners(Object[] signers) {
if (signers != null && signers.length > 0) {
Static.signers.put(this, signers);
if (addendum == null) {
addendum = new Addendum();
}
addendum.signers = signers;
}
}
private static class Static {
public static final Map<Class,Object[]> signers = new HashMap();
private static class Addendum {
public Object[] annotationTable;
public Object[] signers;
}
}

View File

@ -83,7 +83,9 @@ public abstract class ClassLoader {
return c;
}
protected native void resolveClass(Class c);
protected void resolveClass(Class c) {
c.link(this);
}
private ClassLoader getParent() {
return parent;

View File

@ -0,0 +1,16 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.annotation;
@Retention(RetentionPolicy.RUNTIME)
public @interface Retention {
public RetentionPolicy value();
}

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.annotation;
public enum RetentionPolicy {
CLASS, RUNTIME, SOURCE
}

View File

@ -10,9 +10,17 @@
package java.lang.reflect;
public abstract class AccessibleObject {
import java.lang.annotation.Annotation;
public abstract class AccessibleObject implements AnnotatedElement {
protected static final int Accessible = 1 << 0;
public boolean isAnnotationPresent
(Class<? extends Annotation> class_)
{
return getAnnotation(class_) != null;
}
public abstract boolean isAccessible();
public abstract void setAccessible(boolean v);

View File

@ -0,0 +1,23 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
import java.lang.annotation.Annotation;
public interface AnnotatedElement {
public boolean isAnnotationPresent(Class<? extends Annotation> class_);
public <T extends Annotation> T getAnnotation(Class<T> class_);
public Annotation[] getAnnotations();
public Annotation[] getDeclaredAnnotations();
}

View File

@ -10,6 +10,8 @@
package java.lang.reflect;
import java.lang.annotation.Annotation;
public class Constructor<T> extends AccessibleObject
implements Member, GenericDeclaration
{
@ -52,6 +54,18 @@ public class Constructor<T> extends AccessibleObject
return method.isSynthetic();
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
return method.getAnnotation(class_);
}
public Annotation[] getAnnotations() {
return method.getAnnotations();
}
public Annotation[] getDeclaredAnnotations() {
return method.getDeclaredAnnotations();
}
public TypeVariable<Constructor<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}

View File

@ -10,6 +10,10 @@
package java.lang.reflect;
import avian.AnnotationInvocationHandler;
import java.lang.annotation.Annotation;
public class Field<T> extends AccessibleObject {
private static final int VoidField = 0;
private static final int ByteField = 1;
@ -27,7 +31,8 @@ public class Field<T> extends AccessibleObject {
private short flags;
private short offset;
private byte[] name;
private byte[] spec;
public byte[] spec;
public Addendum addendum;
private Class<T> class_;
private Field() { }
@ -195,6 +200,45 @@ public class Field<T> extends AccessibleObject {
}
}
private Annotation getAnnotation(Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
(class_.getClassLoader(), new Class[] { (Class) a[1] },
new AnnotationInvocationHandler(a));
}
return (Annotation) a[0];
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
for (int i = 0; i < table.length; ++i) {
Object[] a = (Object[]) table[i];
if (a[1] == class_) {
return (T) getAnnotation(a);
}
}
}
return null;
}
public Annotation[] getAnnotations() {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
Annotation[] array = new Annotation[table.length];
for (int i = 0; i < table.length; ++i) {
array[i] = getAnnotation((Object[]) table[i]);
}
return array;
} else {
return new Annotation[0];
}
}
public Annotation[] getDeclaredAnnotations() {
return getAnnotations();
}
public boolean isEnumConstant() {
throw new UnsupportedOperationException();
}
@ -210,4 +254,8 @@ public class Field<T> extends AccessibleObject {
private static native void setObject
(Object instance, int offset, Object value);
public static class Addendum {
public Object[] annotationTable;
}
}

View File

@ -0,0 +1,15 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] arguments);
}

View File

@ -10,6 +10,10 @@
package java.lang.reflect;
import avian.AnnotationInvocationHandler;
import java.lang.annotation.Annotation;
public class Method<T> extends AccessibleObject
implements Member, GenericDeclaration
{
@ -21,7 +25,8 @@ public class Method<T> extends AccessibleObject
private short offset;
private int nativeID;
private byte[] name;
private byte[] spec;
public byte[] spec;
public Addendum addendum;
private Class<T> class_;
private Object code;
private long compiled;
@ -142,6 +147,45 @@ public class Method<T> extends AccessibleObject
throw new RuntimeException();
}
private Annotation getAnnotation(Object[] a) {
if (a[0] == null) {
a[0] = Proxy.newProxyInstance
(class_.getClassLoader(), new Class[] { (Class) a[1] },
new AnnotationInvocationHandler(a));
}
return (Annotation) a[0];
}
public <T extends Annotation> T getAnnotation(Class<T> class_) {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
for (int i = 0; i < table.length; ++i) {
Object[] a = (Object[]) table[i];
if (a[1] == class_) {
return (T) getAnnotation(a);
}
}
}
return null;
}
public Annotation[] getAnnotations() {
if (addendum != null && addendum.annotationTable != null) {
Object[] table = addendum.annotationTable;
Annotation[] array = new Annotation[table.length];
for (int i = 0; i < table.length; ++i) {
array[i] = getAnnotation((Object[]) table[i]);
}
return array;
} else {
return new Annotation[0];
}
}
public Annotation[] getDeclaredAnnotations() {
return getAnnotations();
}
public boolean isSynthetic() {
throw new UnsupportedOperationException();
}
@ -165,4 +209,8 @@ public class Method<T> extends AccessibleObject
public TypeVariable<Method<T>>[] getTypeParameters() {
throw new UnsupportedOperationException();
}
public static class Addendum {
public Object[] annotationTable;
}
}

View File

@ -0,0 +1,54 @@
/* Copyright (c) 2009, Avian Contributors
Permission to use, copy, modify, and/or distribute this software
for any purpose with or without fee is hereby granted, provided
that the above copyright notice and this permission notice appear
in all copies.
There is NO WARRANTY for this software. See license.txt for
details. */
package java.lang.reflect;
public class Proxy {
private static int nextNumber;
protected InvocationHandler h;
public static Class getProxyClass(ClassLoader loader,
Class ... interfaces)
{
for (Class c: interfaces) {
if (! c.isInterface()) {
throw new IllegalArgumentException();
}
}
int number;
synchronized (Proxy.class) {
number = nextNumber++;
}
return makeClass
(loader, interfaces, ("Proxy-" + number + "\0").getBytes());
}
private static native Class makeClass(ClassLoader loader,
Class[] interfaces,
byte[] name);
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler handler)
{
try {
return Proxy.getProxyClass(loader, interfaces)
.getConstructor(new Class[] { InvocationHandler.class })
.newInstance(new Object[] { handler });
} catch (Exception e) {
AssertionError error = new AssertionError();
error.initCause(e);
throw error;
}
}
}