View project on GitHub

Reflection in Java has always been difficult, and properly dealing with generic type parameters and annotations nigh impossible. Mirror solves these issues by creating “Mirrors”, which are akin to Java’s core reflection objects with the added fact that type parameters and annotations are considered fully-fledged parts of the type system. Each Mirror is either “unspecialized”, analogous to a raw type in Java, or “specialized” so that each generic type parameter is seamlessly replaced with the argument passed.

// create a mirror of Deque<String>
ClassMirror stringDeque = Mirror.reflectClass(new TypeToken<Deque<String>>() {});

// get the `poll` method
MethodMirror poll = stringList.getMethod("poll");

// the type argument `String` has propagated down and specialized this method's return type
assert poll.getReturnType() == Mirror.reflect(String.class);

// the poll method is actually defined in the `Queue<String>` class
assert poll.getDeclaringClass() == Mirror.reflect(new TypeToken<Queue<String>>() {});

// after the initial overhead of creating the MethodHandle, this should run at near-native speed
String value = poll.call(someStringDeque);
ClassMirror integerLinkedList = Mirror.reflect(new TypeToken<LinkedList<Integer>>() {});
ClassMirror stringList = Mirror.reflect(new TypeToken<List<String>>() {});
ClassMirror numberList = Mirror.reflect(new TypeToken<List<Number>>() {});

// This assignment is valid:
// List<Number> foo = /* some LinkedList<Integer> variable */;
assert numberList.isAssignableFrom(integerLinkedList);

// This assignment is invalid:
// List<String> foo = /* some LinkedList<Integer> variable */;
assert !stringList.isAssignableFrom(integerLinkedList);