Skip to content

Instantly share code, notes, and snippets.

@cmadsen
Last active March 22, 2021 17:08
Show Gist options
  • Save cmadsen/5037405 to your computer and use it in GitHub Desktop.
Save cmadsen/5037405 to your computer and use it in GitHub Desktop.
Use CGLIB proxy to capture method calls and use that to do reflection instead of using strings for reflection. Example here uses this method to create google guava functions and predicates for std POJO method calls. Inspired by [Funcito](http://code.google.com/p/funcito/wiki/CodeGenerationAndProxies)
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
public class ReflectionMethodInterceptor implements MethodInterceptor {
private static final ThreadLocal<Method> lastRegisteredMethod = new ThreadLocal<Method>();
static final Object emptyArgs[] = new Object[0];
public static <T> T newInstance(Class<T> clazz) {
try {
ReflectionMethodInterceptor interceptor = new ReflectionMethodInterceptor();
Enhancer e = new Enhancer();
e.setSuperclass(clazz);
e.setCallback(interceptor);
return (T) e.create();
} catch (Throwable e) {
e.printStackTrace();
throw new Error(e.getMessage());
}
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
lastRegisteredMethod.set(method);
return null;
}
/**
* Returns a Function for the last registered method call on a proxy created
* by {@link newInstance}
*
* <code>
* <br/><br/>
* Function<Person, String> f = functionFor(newInstance(Person.class).getName());
* <br/>
* </code>
*
* @param b
* @return
*/
public static <O, R> Function<O, R> functionFor(R r) {
return new Function<O, R>() {
private Method method = lastRegisteredMethod.get();
public R apply(O object) {
try {
return (R) method.invoke(object, emptyArgs);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
};
}
/**
* Returns a Predicate for the last registered method call on a proxy
* created by {@link newInstance}
*
* <code>
* <br/><br/>
* Predicate<Person> isEmployee = predicateFor(newInstance(Person.class).isEmployee());
* <br/>
* </code>
*
* @param b
* not used
* @return
*/
public static <O> Predicate<O> predicateFor(boolean b) {
return new Predicate<O>() {
private Method method = lastRegisteredMethod.get();
public boolean apply(O object) {
try {
return (Boolean) method.invoke(object, emptyArgs);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
};
}
public static class Person {
public String getName() {
return "Hans Hansen";
}
public boolean isEmployee() {
return true;
}
}
public static void main(String[] args) {
Person callsToPersonRegistrant = newInstance(Person.class);
Function<Person, String> personName = functionFor(callsToPersonRegistrant
.getName());
System.out.println(personName.apply(new Person()));
Predicate<Person> isEmployee = predicateFor(callsToPersonRegistrant
.isEmployee());
System.out.println("isEmployee " + isEmployee.apply(new Person()));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment