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;
}
}
2 comments:
This information could be made more useful if you also provided a simple example on how to use it.
Sorry for the poor formatting on this site, but here is a followup providing sample use of this example for anyone who follows behind me.
public class Test {
public void Test() {}
public static void main(String[] args) throws Exception {
Test obj = new Test(); // a dummy object to pass
Callback method;
method = new Callback(Test.class, "ClassCallBackWithoutParam", null);
method.call();
method = new Callback(Test.class, "ClassCallBackWithParam", null, String.class);
method.call("hello");
method = new Callback(Test.class, "MemberCallBackWithoutParam", obj);
method.call();
method = new Callback(Test.class, "MemberCallBackWithParam", obj, String.class);
method.call("hello");
method = new Callback(Test.class, "MemberCallBackWithParameters", obj, String.class, int.class, Long.class);
method.call("hello", 1, (Long)1234567890L);
}
public static void ClassCallBackWithoutParam() {
System.out.println("Method.ClassCallBackWithoutParam");
}
public static void ClassCallBackWithParam(String msg) {
System.out.println("Method.ClassCallBackWithParam got '" + msg + "\"'");
}
public void MemberCallBackWithoutParam() {
System.out.println("Method.MemberCallBackWithoutParam");
}
public void MemberCallBackWithParam(String msg) {
System.out.println("Method.MemberCallBackWithParam got '" + msg + "\"'");
}
public void MemberCallBackWithParameters(String msg, int value, Long longvalue) {
System.out.println("Method.MemberCallBackWithParam got '" + msg + "' int: " + value + ", Long: " + longvalue);
}
}
Post a Comment