reflect
Gentle reflection of types, names and resources
Consists of static methods across four classes:
- Methods
- All methods of a given class (inherited, overridden)
- Easily acquire a MethodHandle (works in Java 8, 9 and 10)
- Names
- Class names to/from binary, descriptor and resource
- Resources
- Get the bytecode for a class
- Find a class’ location
- Types
- Overloaded to accept java.lang.Class, java.lang.reflect.Type and java.lang.String
- isA methods for primitive, primitive-wrapper, interface and class
- Find all interfaces/supertypes
- Query implements/extends
- Convert primitives to/from wrappers
- requiresInterface/requiresClass argument checkers
Examples
Method handle
Find a method and then get a handle for it:
public String taDa() { return "TA-DA"; } @Test public void handleForNormalMethod() throws Throwable { Method method = Methods.getMethod(MethodsTest.class, "taDa") .orElseThrow(NullPointerException::new); MethodHandle handle = Methods.handleFor(method).bindTo(this); assertThat(handle.invoke(), is(equalTo(taDa()))); }
(source)
Find resource
For a given class, locate it’s origin, in a directory:
String resource = Resources.sourceOfResource(ResourcesTest.class); assertThat(resource, new File(resource), is(anExistingDirectory())); assertThat(resource, endsWith("/target/test-classes/"));
Or in a JAR:
String resource = Resources.sourceOfResource(Immutable.class); assertThat(new File(resource), is(aReadableFile())); assertThat(resource, allOf( containsString("/com/google/code/findbugs/jsr305/"), endsWith(".jar")));
(source)
Names
Get a binary name for a type:
String typeToDescriptor = Names.typeToDescriptor(Map.Entry.class).toString(); assertThat(typeToDescriptor, is(equalTo("Ljava/util/Map$Entry;")));
Get a binary name for a type:
String binaryName = Names.internalToTypeName("[[Ljava/lang/Object;"); assertThat(binaryName, is(equalTo(Object[][].class.getTypeName())));
List all binary names declared within a compilation unit:
Given:
private class Declares { private class DeclaredTop { private class DeclaredMiddle { private class DeclaredBottom {} private final Comparator<String> anon = new Comparator<String>() { @Override public int compare(String o1, String o2) { return 0; } }; public String x() { Supplier<String> supplier = new Supplier<String>() { @Override public String get() { return "hello"; } }; return supplier.get(); } } } }
We shall use:
List<String> classes = Names.declaredInternalNamesOf(Declares.class).collect(toList()); assertThat(classes, containsInAnyOrder( typeToInternalName(Declares.DeclaredTop.class), typeToInternalName(Declares.DeclaredTop.DeclaredMiddle.class), typeToInternalName(Declares.DeclaredTop.DeclaredMiddle.class) + "$1", typeToInternalName(Declares.DeclaredTop.DeclaredMiddle.class) + "$2", typeToInternalName(Declares.DeclaredTop.DeclaredMiddle.DeclaredBottom.class)));
(source)
Types
Argument checking requires* methods, such as:
try { requireClass(Comparable.class); fail(); } catch(IllegalArgumentException e) {}
Query methods, such as:
assertThat(Types.implementsAll(String.class, Serializable.class, Comparable.class, CharSequence.class), is(true));
(source)