I need to pass an arbitrary Java method to another class where it will be executed asynchronously. I have a feeling I can use lambda functions as the parameters of my call method, but I'm not sure if I need to create a functional interface for it. I will also need to typecheck the response.
private Object foo(String method, Object...args){
try{
result.set( connection.invoke(method, args) );
} catch (InterruptedException e) {
}
return result.get();
}
I noticed someone wanted to do something similar here, but I need to pass an arbitrary number of arguments (BiConsumer only works for 2). I don't know how many arguments I will need call to accept.
I also need to typecheck the response, and everything I've found so far regarding Java typechecking says this is not possible. Is it?
You can make varargs methods with the following signature:
interface Invokable extends FunctionalInterface {
Object invoke(Object... arguments);
}
Primitive can be passed as argument since they will be auto boxed to their object equivalent (int -> Integer, long -> Long, and so on).
However, you will be forced to use cast to do type checking.
What I recommend instead is to use an Object
containing the arguments and to parametrize the functional interface:
interface Argument<R> {
// Empty interface used to mark argument types.
}
interface Invokable<R, A extends Argument<R>> extends FunctionalInterface {
R invoke(A argument);
}
And then change your foo
method to find the method to call depending on the argument class. Like so:
private <A, R> R foo(A arg) {
if (arg != null) {
// TODO: Use injection or a map to create a relation between Class<A> and its Invokable<A, R>.
final Invokable<A, R> invokable = invokables.get(a.getClass());
try {
return invokable.invoke(arg); // Type checked result (R).
} catch (InterruptedException e) {
// TODO: Handle exception.
}
}
return null;
}
This pattern is usually called the Command pattern.