corda/test/Reflection.java
Joel Dice 25d69f38ee match Java's schizophrenic concept of inner class access modifiers
An inner class has two sets of modifier flags: one is declared in the
usual place in the class file and the other is part of the
InnerClasses attribute.  Not only is that redundant, but they can
contradict, and the VM can't just pick one and roll with it.  Instead,
Class.getModifiers must return the InnerClasses version, whereas
reflection must check the top-level version.  So even if
Class.getModifiers says the class is protected, it might still be
public for the purpose of reflection depending on what the
InnerClasses attribute says.  Crazy?  Yes.
2014-03-06 16:17:43 -07:00

266 lines
7.0 KiB
Java

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.InvocationTargetException;
public class Reflection {
public static boolean booleanMethod() {
return true;
}
public static byte byteMethod() {
return 1;
}
public static char charMethod() {
return '2';
}
public static short shortMethod() {
return 3;
}
public static int intMethod() {
return 4;
}
public static float floatMethod() {
return 5.0f;
}
public static long longMethod() {
return 6;
}
public static double doubleMethod() {
return 7.0;
}
public static void expect(boolean v) {
if (! v) throw new RuntimeException();
}
private static class Hello<T> {
private class World<S> { }
}
private static void innerClasses() throws Exception {
Class c = Reflection.class;
Class[] inner = c.getDeclaredClasses();
expect(2 == inner.length);
expect(Hello.class == inner[0]
|| Hello.class == inner[1]);
}
private int egads;
private static void annotations() throws Exception {
Field egads = Reflection.class.getDeclaredField("egads");
expect(egads.getAnnotation(Deprecated.class) == null);
}
private Integer[] array;
private Integer integer;
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 throwOOME() {
throw new OutOfMemoryError();
}
public static void main(String[] args) throws Exception {
innerClasses();
annotations();
genericType();
Class system = Class.forName("java.lang.System");
Field out = system.getDeclaredField("out");
Class output = Class.forName("java.io.PrintStream");
Method println = output.getDeclaredMethod("println", String.class);
println.invoke(out.get(null), "Hello, World!");
expect((Boolean) Reflection.class.getMethod("booleanMethod").invoke(null));
expect(1 == (Byte) Reflection.class.getMethod("byteMethod").invoke(null));
expect('2' == (Character) Reflection.class.getMethod
("charMethod").invoke(null));
expect(3 == (Short) Reflection.class.getMethod
("shortMethod").invoke(null));
expect(4 == (Integer) Reflection.class.getMethod
("intMethod").invoke(null));
expect(5.0 == (Float) Reflection.class.getMethod
("floatMethod").invoke(null));
expect(6 == (Long) Reflection.class.getMethod
("longMethod").invoke(null));
expect(7.0 == (Double) Reflection.class.getMethod
("doubleMethod").invoke(null));
{ Class[][] array = new Class[][] { { Class.class } };
expect("[Ljava.lang.Class;".equals(array[0].getClass().getName()));
expect(Class[].class == array[0].getClass());
expect(array.getClass().getComponentType() == array[0].getClass());
}
{ Reflection r = new Reflection();
expect(r.egads == 0);
Reflection.class.getDeclaredField("egads").set(r, (Integer)42);
expect(((Integer)Reflection.class.getDeclaredField("egads").get(r)) == 42);
Reflection.class.getDeclaredField("egads").setInt(r, 43);
expect(Reflection.class.getDeclaredField("egads").getInt(r) == 43);
Integer[] array = new Integer[0];
Reflection.class.getDeclaredField("array").set(r, array);
expect(Reflection.class.getDeclaredField("array").get(r) == array);
try {
Reflection.class.getDeclaredField("array").set(r, new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
Integer integer = 45;
Reflection.class.getDeclaredField("integer").set(r, integer);
expect(Reflection.class.getDeclaredField("integer").get(r) == integer);
try {
Reflection.class.getDeclaredField("integer").set(r, new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
try {
Reflection.class.getDeclaredField("integer").set
(new Object(), integer);
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
try {
Reflection.class.getDeclaredField("integer").get(new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
}
}
try {
Foo.class.getMethod("foo").invoke(null);
expect(false);
} catch (ExceptionInInitializerError e) {
expect(e.getCause() instanceof MyException);
}
try {
Foo.class.getConstructor().newInstance();
expect(false);
} catch (NoClassDefFoundError e) {
// cool
}
try {
Foo.class.getField("foo").get(null);
expect(false);
} catch (NoClassDefFoundError e) {
// cool
}
try {
Foo.class.getField("foo").set(null, (Integer)42);
expect(false);
} catch (NoClassDefFoundError e) {
// cool
}
try {
Foo.class.getField("foo").set(null, new Object());
expect(false);
} catch (IllegalArgumentException e) {
// cool
} catch (NoClassDefFoundError e) {
// cool
}
{ Method m = Reflection.class.getMethod("throwOOME");
try {
m.invoke(null);
} catch(Throwable t) {
expect(t.getClass() == InvocationTargetException.class);
}
}
expect((Foo.class.getMethod("toString").getModifiers()
& Modifier.PUBLIC) != 0);
expect(avian.TestReflection.get(Baz.class.getField("foo"), new Baz())
.equals(42));
expect((Baz.class.getModifiers() & Modifier.PUBLIC) == 0);
}
protected static class Baz {
public int foo = 42;
}
}
class Foo {
static {
if (true) throw new MyException();
}
public Foo() { }
public static int foo;
public static void foo() {
// ignore
}
}
class MyException extends RuntimeException { }