Skip to content

Instantly share code, notes, and snippets.

@kogupta
Created June 14, 2018 04:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kogupta/dc7ee0cd361d6564dab25a2ffebbe343 to your computer and use it in GitHub Desktop.
Save kogupta/dc7ee0cd361d6564dab25a2ffebbe343 to your computer and use it in GitHub Desktop.
bean introspection using lambda metafactory
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Function;
/**
* Fetch the `get` methods of a bean/pojo.
* Same thing can be achieved by bean introspection as well.
*
* @param <T>
*/
public final class PojoGetters<T> {
private final Map<String, Function> getters;
private PojoGetters(Class<T> clazz) {
this.getters = new LinkedHashMap<>();
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (method.getName().startsWith("get")) {
getters.put(method.getName(), getter(method));
}
}
}
private static Function getter(Method method) {
try {
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodHandle handle = caller.unreflect(method);
return (Function) LambdaMetafactory.metafactory(
caller,
"apply",
MethodType.methodType(Function.class),
MethodType.methodType(Object.class, Object.class),
handle,
handle.type())
.getTarget()
.invoke();
} catch (Throwable e) {
throw new RuntimeException("Could not generate the function to access the getter " + method.getName(), e);
}
}
/**
* Given field `price` returns method name `getPrice`
*
* @param fieldName
* @return method name of getter corresponding to field
*/
private static String getterName(String fieldName) {
char oldChar = fieldName.charAt(0);
char upperCase = Character.toUpperCase(oldChar);
String methodName = "get" + upperCase + fieldName.substring(1);
// System.out.println("Method name: " + methodName);
return methodName;
}
public Object invokeByGetter(T instance, String methodName) {
Function fn = getters.get(methodName);
return fn.apply(instance);
}
public Object invokeByField(T instance, String field) {
return invokeByGetter(instance, getterName(field));
}
public static <T> PojoGetters<T> of(Class<T> clazz) {
return new PojoGetters<>(clazz);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment