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)