Skip to content

Commit

Permalink
support runtime-visible annotations and java.lang.reflect.Proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
Joel Dice committed Sep 19, 2009
1 parent a2a33c2 commit 7aa906d
Show file tree
Hide file tree
Showing 23 changed files with 1,278 additions and 169 deletions.
31 changes: 31 additions & 0 deletions classpath/avian/AnnotationInvocationHandler.java
@@ -0,0 +1,31 @@
/* 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 avian;

import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;

public class AnnotationInvocationHandler implements InvocationHandler {
private Object[] data;

public AnnotationInvocationHandler(Object[] data) {
this.data = data;
}

public Object invoke(Object proxy, Method method, Object[] arguments) {
for (int i = 2; i < data.length; i += 2) {
if (method.getName().equals(data[i])) {
return data[i + 1];
}
}
throw new IllegalArgumentException();
}
}
16 changes: 16 additions & 0 deletions classpath/avian/Pair.java
@@ -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 avian;

public class Pair<A,B> {
public A first;
public B second;
}
256 changes: 242 additions & 14 deletions classpath/java/lang/Class.java
Expand Up @@ -10,14 +10,20 @@


package java.lang; package java.lang;


import avian.AnnotationInvocationHandler;
import avian.Pair;

import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable; import java.lang.reflect.TypeVariable;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.GenericDeclaration; import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.AnnotatedElement;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.io.InputStream; import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
Expand All @@ -28,8 +34,11 @@
import java.security.Permissions; import java.security.Permissions;
import java.security.AllPermission; 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 PrimitiveFlag = 1 << 5;
private static final int LinkFlag = 1 << 8;


private short flags; private short flags;
private short vmFlags; private short vmFlags;
Expand All @@ -44,6 +53,7 @@ public final class Class <T> implements Type, GenericDeclaration {
private Method[] virtualTable; private Method[] virtualTable;
private Field[] fieldTable; private Field[] fieldTable;
private Method[] methodTable; private Method[] methodTable;
private Addendum addendum;
private Object staticTable; private Object staticTable;
private ClassLoader loader; private ClassLoader loader;


Expand Down Expand Up @@ -139,6 +149,157 @@ public T newInstance()
} }
} }


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 { public static Class forName(String name) throws ClassNotFoundException {
return forName return forName
(name, true, Method.getCaller().getDeclaringClass().getClassLoader()); (name, true, Method.getCaller().getDeclaringClass().getClassLoader());
Expand All @@ -161,8 +322,6 @@ public static Class forName(String name, boolean initialize,


private static native Class primitiveClass(char name); private static native Class primitiveClass(char name);


private native void link(ClassLoader loader);

private native void initialize(); private native void initialize();


public static Class forCanonicalName(String name) { public static Class forCanonicalName(String name) {
Expand Down Expand Up @@ -479,9 +638,10 @@ public Class[] getInterfaces() {
if (interfaceTable != null) { if (interfaceTable != null) {
link(loader); 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) { for (int i = 0; i < array.length; ++i) {
array[i] = (Class) interfaceTable[i * 2]; array[i] = (Class) interfaceTable[i * stride];
} }
return array; return array;
} else { } else {
Expand Down Expand Up @@ -566,7 +726,7 @@ public T cast(Object o) {
} }


public Object[] getSigners() { public Object[] getSigners() {
return Static.signers.get(this); return addendum == null ? null : addendum.signers;
} }


public Package getPackage() { public Package getPackage() {
Expand All @@ -584,8 +744,76 @@ public Package getPackage() {
} }
} }


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() { 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() { public boolean isEnum() {
Expand All @@ -612,10 +840,6 @@ public Class[] getDeclaredClasses() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }


public <A extends Annotation> A getAnnotation(Class<A> c) {
throw new UnsupportedOperationException();
}

public ProtectionDomain getProtectionDomain() { public ProtectionDomain getProtectionDomain() {
Permissions p = new Permissions(); Permissions p = new Permissions();
p.add(new AllPermission()); p.add(new AllPermission());
Expand All @@ -625,11 +849,15 @@ public ProtectionDomain getProtectionDomain() {
// for GNU Classpath compatibility: // for GNU Classpath compatibility:
void setSigners(Object[] signers) { void setSigners(Object[] signers) {
if (signers != null && signers.length > 0) { if (signers != null && signers.length > 0) {
Static.signers.put(this, signers); if (addendum == null) {
addendum = new Addendum();
}
addendum.signers = signers;
} }
} }


private static class Static { private static class Addendum {
public static final Map<Class,Object[]> signers = new HashMap(); public Object[] annotationTable;
public Object[] signers;
} }
} }
4 changes: 3 additions & 1 deletion classpath/java/lang/ClassLoader.java
Expand Up @@ -83,7 +83,9 @@ protected Class loadClass(String name, boolean resolve)
return c; return c;
} }


protected native void resolveClass(Class c); protected void resolveClass(Class c) {
c.link(this);
}


private ClassLoader getParent() { private ClassLoader getParent() {
return parent; return parent;
Expand Down

0 comments on commit 7aa906d

Please sign in to comment.