Java does not have callbacks. Most commonly, I see people working around this by implementing the Observer Pattern, or simply having an interface for each method they need to use as a callback.
On a recent project, I felt the need for more direct callbacks in my Java code. Java's reflection package seemed to hold my answer. Given a Class, a method name, and (in the case of overloaded methods) a list of parameter types, you can retrieve an instance of the Method class. Then, given a list of arguments to pass to the method, it can be invoked via reflection.
Java reflection isn't particularly fast, so I recommend against this approach in applications where performance is important. But reflection works, so I present my Callback class here:
package com.bs;
import java.lang.reflect.*;
/**
* Implements callback functionality for Java.
* Callbacks are implemented using reflection, so should
* be avoided if possible.
*
* @author Brian Shields <http://clockworkgear.blogspot.com/>
*/
public class Callback {
private Object parentObj;
private Method method;
private Class<?>[] parameters;
public Callback(Class<?> clazz, String methodName, Object parentObj) {
// Find a method with the matching name
Method[] allMethods;
try { allMethods = clazz.getMethods(); }
catch(SecurityException se) { allMethods = new Method[0]; }
int count = 0;
Method single = null;
for(Method m : allMethods) {
if(m.getName().equals(methodName)) {
single = m;
count++;
}
// Can't have more than one instance
if(count > 1)
throw new IllegalArgumentException(clazz.getName()
+ " has more than one method named " + methodName);
}
if(count == 0) // No instances found
throw new IllegalArgumentException(clazz.getName()
+ " has no method named " + methodName);
this.parentObj = parentObj;
this.method = single;
this.parameters = single.getParameterTypes();
}
public Callback(
Class<?> clazz,
String methodName,
Object parentObj,
Class<?>...parameters)
{
try { this.method = clazz.getMethod(methodName, parameters); }
catch(NoSuchMethodException nsme) { nsme.printStackTrace(); }
catch(SecurityException se) { se.printStackTrace(); }
this.parentObj = parentObj;
this.parameters = parameters;
}
public Object call(Object...vals) {
if(parameters.length != vals.length)
throw new IllegalArgumentException(
"Wrong number of method parameters given. Found "
+ vals.length + ", expected " + parameters.length);
Object ret = null;
try { ret = method.invoke(parentObj, vals); }
catch(IllegalAccessException iae) { iae.printStackTrace(); }
catch(InvocationTargetException ite) { ite.printStackTrace(); }
return ret;
}
}