Skip to content

Instantly share code, notes, and snippets.

@josefbetancourt
Created March 5, 2013 01:47
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save josefbetancourt/3ffcb3044e558fc1b3e8 to your computer and use it in GitHub Desktop.
Save josefbetancourt/3ffcb3044e558fc1b3e8 to your computer and use it in GitHub Desktop.
Here is an example of creating a fluent builder interface for invoking a method via Java Reflection. While the code to invoke Java methods via reflection is not complex, it can be improved. We can introduce a ‘façade’ and this façade can use the fluent builder pattern. One example of using this is: .name(“greet”).on(anObject).with(“Hello world!”…
/**
*
*/
package com.octodecillion.utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
/**
* Reflection Invoker using Fluent Builder.
*
* Example is a singleton utility class that contains
* one utility that is used in a fluent builder pattern.
*
* @author jbetancourt
* @since 20130201T2233-5
*
*/
public final class ReflectionUtil {
private static final ReflectionUtil instance = new ReflectionUtil();
private ReflectionUtil() {
// it's a singleton utility class.
}
public static Invoker invokes() {
return instance.new Invoker();
}
/**
* Example use:
* invokes().name("hello").on(innerTest).using("Hello world!").of(String.class).invoke();
*
*/
class Invoker {
private String name;
private Object object;
private Class<? extends Object> clazz;
private Class<?>[] classes;
private Object[] params;
private Method method;
private boolean allowPrivate;
public Invoker name(final String name) {
this.name = name;
return this;
}
public Invoker on(final Object obj) {
object = obj;
return this;
}
public Invoker on(final Class<?> clz) {
clazz = clz;
return this;
}
public Invoker of(final Class<?>... classes) {
this.classes = classes;
return this;
}
public Invoker using(final Object... params) {
this.params = params;
return this;
}
public Invoker nosy() {
allowPrivate = true;
return this;
}
public Invoker method(final Method method) {
this.method = method;
return this;
}
public <T> Invoker returning(@SuppressWarnings("unused") final T clazz) {
return this;
}
public Object invoke() throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
boolean paramsButNoTypes = (method == null)
&& ((params != null) && (classes == null));
if (paramsButNoTypes) {
throw new IllegalStateException(String.format(
"params:%s,classes:%s", params, classes));
}
if (method == null) {
if (object == null) {
method = clazz.getDeclaredMethod(name, classes);
} else {
Class<? extends Object> clz = (clazz == null ? object
.getClass() : clazz);
method = clz.getDeclaredMethod(name, classes);
}
}
if (allowPrivate) {
return invokePrivate();
}
return method.invoke(object, params);
}
private Object invokePrivate() {
try {
final Object objF = object;
final Method methodF = method;
final Object[] paramsF = params;
return AccessController
.doPrivileged(new PrivilegedExceptionAction<Object>() {
Object result;
@Override
public Object run() throws Exception {
if (!methodF.isAccessible()) {
methodF.setAccessible(true);
}
result = methodF.invoke(objF, paramsF);
return result;
}
});
} catch (Exception ex) {
throw new IllegalStateException("Cannot set method,'" + method
+ "' accessible.", ex);
}
}
} // end class Invoker
} // end class Example
/**
*
*/
package com.octodecillion.utils;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
*
*
* @author jbetancourt
*
*/
@RunWith(JUnit4.class)
public class ReflectionUtilTest {
/** test on class with static public methods */
@Test
public final void invokes_on_static() throws Exception {
Object actual = ReflectionUtil.invokes().name("hello")
.on(WithStaticMethod.class).using("Hello world!")
.of(String.class).invoke();
assertThat((String) actual, is("Hello world!"));
}
/** test on class with static private methods */
@Test
public final void invokes_on_private_method() throws Exception {
WithStaticMethod obj = new WithStaticMethod();
Object actual = ReflectionUtil.invokes().name("privateHello").on(obj).nosy()
.invoke();
assertThat((String) actual, is("Hello private world!"));
}
static class WithStaticMethod {
public static String hello(final String msg) {
return msg;
}
private String privateHello() {
return "Hello private world!";
}
}
/** test on inner class with public methods */
@Test
public final void testInvokes() throws Exception {
class InnerClass {
public String hello(final String msg) {
return msg;
}
public String hello() {
return "Hello default world!";
}
private String privateHello() {
return "Hello private world!";
}
} // end InnerTest
InnerClass innerTest = new InnerClass();
Object actual = ReflectionUtil.invokes().name("hello").on(innerTest)
.using("Hello world!").of(String.class).invoke();
assertThat((String) actual, is("Hello world!"));
actual = ReflectionUtil.invokes().name("hello").on(innerTest).invoke();
assertThat((String) actual, is("Hello default world!"));
actual = ReflectionUtil.invokes().name("privateHello").on(innerTest).nosy()
.invoke();
assertThat((String) actual, is("Hello private world!"));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment