A neater way to use reflection in Java
Reflection in Java really feels awkward. The java.lang.reflect API is very powerful and complete, and in that sense also very verbose. Unlike in most scripting languages, there is no convenient way to access methods and fields dynamically using reflection. By convenient, I mean things like this
// PHP $method = 'my_method'; $field = 'my_field'; // Dynamically call a method $object->$method(); // Dynamically access a field $object->$field;
Or even better
// JavaScript var method = 'my_method'; var field = 'my_field'; // Dynamically call a function object[method](); // Dynamically access a field object[field];
For us Java guys, this is something we can only dream of. We would write this
String method = "my_method"; String field = "my_field"; // Dynamically call a method object.getClass().getMethod(method).invoke(object); // Dynamically access a field object.getClass().getField(field).get(object);
Obviously, this doesn’t take care of NullPointerExceptions, InvocationTargetExceptions, IllegalAccessExceptions, IllegalArgumentExceptions, SecurityExceptions, primitive types, etc. In an enterprise world, things need to be safe and secure, and the Java architects have thought of all possible problems that could arise when using reflection. But in many cases, we know what we’re doing and we don’t care about most of those features. We’d prefer the less verbose way.
That’s why I have created another sibling in the jOO* family: jOOR (Java Object Oriented Reflection). While this is not a killer libary, it might be useful for 1-2 developers out there looking for a simple and fluent solution. Here’s an example I have recently encountered on stack overflow, where jOOR might fit in just perfectly:
// Classic example of reflection usage
try {
Method m1 = department.getClass().getMethod("getEmployees");
Employee employees = (Employee[]) m1.invoke(department);
for (Employee employee : employees) {
Method m2 = employee.getClass().getMethod("getAddress");
Address address = (Address) m2.invoke(employee);
Method m3 = address.getClass().getMethod("getStreet");
Street street = (Street) m3.invoke(address);
System.out.println(street);
}
}
// There are many checked exceptions that you are likely to ignore anyway
catch (Exception ignore) {
// ... or maybe just wrap in your preferred runtime exception:
throw new RuntimeException(e);
}
And the same example using jOOR:
Employee[] employees = on(department).call("getEmployees").get();
for (Employee employee : employees) {
Street street = on(employee).call("getAddress").call("getStreet").get();
System.out.println(street);
}
See the full Stack Overflow question here:
http://stackoverflow.com/questions/4385003/java-reflection-open-source/8672186
Another example:
String world =
on("java.lang.String") // Like Class.forName()
.create("Hello World") // Call the most specific matching constructor
.call("substring", 6) // Call the most specific matching method
.call("toString") // Call toString()
.get() // Get the wrapped object, in this case a String
Get jOOR for free here:
http://code.google.com/p/joor/
From http://lukaseder.wordpress.com/2011/12/29/a-neater-way-to-use-reflection-in-java/




Comments
Andy Till replied on Thu, 2012/01/12 - 7:58am
Wladimir Mangelardo replied on Thu, 2012/01/12 - 9:46am
Xavier Dury replied on Thu, 2012/01/12 - 10:14am
Arnaud Des_vosges replied on Thu, 2012/01/12 - 12:02pm
public static INTF createProxy(final TARGET target, Class(INTF) interf) { final Class targetClass = target.getClass(); InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Method targetMethod = targetClass.getMethod( method.getName(), method.getParameterTypes()); return targetMethod.invoke(target, args); } }; return (INTF)Proxy.newProxyInstance( interf.getClassLoader(), new Class[]{interf}, handler ); } interface DepartmentHelper { Employee[] getEmployees(); Address getAddress(); } Object anyObject = ... DepartmentHelper department = createProxy(anyObject, DepartmentHelper.class); Employee[] employees = department .getEmployees(); Address addr = department .getAddress();Thomas Berger replied on Fri, 2012/01/13 - 4:32am
I think the following line
Street street = on(employee).call("getAddress").call("getStreet");should be
Street street = on(employee).call("getAddress").call("getStreet").get();Lukas Eder replied on Fri, 2012/01/13 - 5:20am
in response to: tb3rg3r
Lukas Eder replied on Fri, 2012/01/13 - 5:20am
in response to: arnaudm
Arnaud Des_vosges replied on Fri, 2012/01/13 - 6:56am
in response to: lukas.eder@gmail.com
Extreme Java replied on Fri, 2012/01/13 - 8:24am
Martijn Verburg replied on Sat, 2012/01/14 - 11:14am
Lukas Eder replied on Sat, 2012/01/14 - 1:26pm
in response to: karianna
Lukas Eder replied on Sat, 2012/01/14 - 1:59pm
in response to: arnaudm
Using the InvocationHandler and Proxy along with jOOR looks great! Your method can be wrapped like this:
@SuppressWarnings("unchecked") public <P> P as(Class<P> proxyType) { final InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return on(object).call(method.getName(), args).get(); } }; return (P) Proxy.newProxyInstance(proxyType.getClassLoader(), new Class[] { proxyType }, handler); }Which can then be used in jOOR like this:
Employee[] employees = on(department).as(DepartmentHelper.class).getEmployees(); for (Employee employee : employees) { Street street = on(employee).as(EmployeeHelper.class).getAddress().getStreet(); System.out.println(street); }Arnaud Des_vosges replied on Mon, 2012/01/16 - 11:17am
in response to: lukas.eder@gmail.com
It's also possible to automatically wrap the result of the method (using the declared return type of the helper method) and also unwrap arguments if needed. That would implement a kind of "membrane" pattern. (Primitives and non-interface types would not be wrapped. Also wrapping would be avoided if the returned object directly implements the declared return type of the helper.)
interface DepartmentHelper { List<EmployeeHelper> getEmployees(); // instead of List<Employee> getEmployees() void add(EmployeeHelper employee); // instead of add(Employee) ... } List<EmployeeHelper> employees = on(department).as(DepartmentHelper.class).getEmployees(); // wrap returned intf on(otherDepartment).add(employees.get(0)); // unwrap argLukas Eder replied on Tue, 2012/01/17 - 1:07pm
in response to: arnaudm
Hi Arnaud,
Feel free to provide a patch! :-)
Cheers,
Lukas
Arnaud Des_vosges replied on Thu, 2012/01/19 - 6:22am
in response to: lukas.eder@gmail.com