Implement Field#getGenericType()

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin 2013-12-03 14:08:21 -06:00
parent 0eb2d55da2
commit 2d83622975
4 changed files with 200 additions and 3 deletions

View File

@ -66,6 +66,14 @@ public class Field<T> extends AccessibleObject {
new String(vmField.spec, 0, vmField.spec.length - 1, false));
}
public Type getGenericType() {
if (vmField.addendum == null || vmField.addendum.signature == null) {
return getType();
}
String signature = Classes.toString((byte[]) vmField.addendum.signature);
return SignatureParser.parse(vmField.class_.loader, signature);
}
public Object get(Object instance) throws IllegalAccessException {
Object target;
if ((vmField.flags & Modifier.STATIC) != 0) {

View File

@ -0,0 +1,17 @@
/* Copyright (c) 2008-2013, 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 ParameterizedType extends Type {
Type[] getActualTypeArguments();
Type getOwnerType();
Type getRawType();
}

View File

@ -0,0 +1,135 @@
/* Copyright (c) 2008-2013, 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.util.ArrayList;
import java.util.List;
class SignatureParser {
private final ClassLoader loader;
private final char[] array;
private int offset;
private final Type type;
static Type parse(ClassLoader loader, String signature) {
return new SignatureParser(loader, signature).type;
}
private SignatureParser(ClassLoader loader, String signature) {
this.loader = loader;
array = signature.toCharArray();
type = parseType();
if (offset != array.length) {
throw new IllegalArgumentException("Extra characters after " + offset
+ ": " + signature);
}
}
private Type parseType() {
char c = array[offset++];
if (c == 'B') {
return Byte.TYPE;
} else if (c == 'C') {
return Character.TYPE;
} else if (c == 'D') {
return Double.TYPE;
} else if (c == 'F') {
return Float.TYPE;
} else if (c == 'I') {
return Integer.TYPE;
} else if (c == 'J') {
return Long.TYPE;
} else if (c == 'S') {
return Short.TYPE;
} else if (c == 'Z') {
return Boolean.TYPE;
} else if (c != 'L') {
throw new IllegalArgumentException("Unexpected character: " + c);
}
StringBuilder builder = new StringBuilder();
Type ownerType = null;
for (;;) {
for (;;) {
c = array[offset++];
if (c == ';' || c == '<') {
break;
}
builder.append(c == '/' ? '.' : c);
}
String rawTypeName = builder.toString();
Class<?> rawType;
try {
rawType = loader.loadClass(rawTypeName);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Could not find class " + rawTypeName);
}
if (c == ';') {
return rawType;
}
List<Type> args = new ArrayList<Type>();
while (array[offset] != '>') {
args.add(parseType());
}
++offset;
c = array[offset++];
ParameterizedType type = makeType(args.toArray(new Type[args.size()]), ownerType, rawType);
if (c == ';') {
return type;
}
if (c != '.') {
throw new RuntimeException("TODO");
}
ownerType = type;
builder.append("$");
}
}
private static String typeName(Type type) {
if (type instanceof Class) {
Class<?> clazz = (Class<?>) type;
return clazz.getName();
}
return type.toString();
}
private static ParameterizedType makeType(final Type[] args, final Type owner, final Type raw) {
return new ParameterizedType() {
@Override
public Type getRawType() {
return raw;
}
@Override
public Type getOwnerType() {
return owner;
}
@Override
public Type[] getActualTypeArguments() {
return args;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(typeName(raw));
builder.append('<');
String sep = "";
for (Type t : args) {
builder.append(sep).append(typeName(t));
sep = ", ";
}
builder.append('>');
return builder.toString();
}
};
}
}

View File

@ -1,5 +1,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class Reflection {
public static boolean booleanMethod() {
@ -38,8 +40,8 @@ public class Reflection {
if (! v) throw new RuntimeException();
}
private static class Hello {
private class World { }
private static class Hello<T> {
private class World<S> { }
}
private static void innerClasses() throws Exception {
@ -56,9 +58,44 @@ public class Reflection {
expect(egads.getAnnotation(Deprecated.class) == null);
}
public static Hello<Hello<Reflection>>.World<Hello<String>> pinky;
private static void genericType() throws Exception {
Field field = Reflection.class.getDeclaredField("egads");
expect(field.getGenericType() == Integer.TYPE);
field = Reflection.class.getField("pinky");
expect("Reflection$Hello$World".equals(field.getType().getName()));
expect(field.getGenericType() instanceof ParameterizedType);
ParameterizedType type = (ParameterizedType) field.getGenericType();
expect(type.getRawType() instanceof Class);
Class<?> clazz = (Class<?>) type.getRawType();
expect("Reflection$Hello$World".equals(clazz.getName()));
expect(type.getOwnerType() instanceof ParameterizedType);
ParameterizedType owner = (ParameterizedType) type.getOwnerType();
clazz = (Class<?>) owner.getRawType();
expect(clazz == Hello.class);
Type[] args = type.getActualTypeArguments();
expect(1 == args.length);
expect(args[0] instanceof ParameterizedType);
ParameterizedType arg = (ParameterizedType) args[0];
expect(arg.getRawType() instanceof Class);
clazz = (Class<?>) arg.getRawType();
expect("Reflection$Hello".equals(clazz.getName()));
args = arg.getActualTypeArguments();
expect(1 == args.length);
expect(args[0] == String.class);
}
public static void main(String[] args) throws Exception {
innerClasses();
annotations();
genericType();
Class system = Class.forName("java.lang.System");
Field out = system.getDeclaredField("out");