How to find an overloaded method in Java? - java

When writing something like
doit(43, 44, "hello");
the compiler knows which overloaded method is to be called. When I want to do the same via reflection, I need to find out myself, that the method is
doit(Integer, double, CharSequence...);
and obtain it via something like
Class[] types = {Integer.class, double.class, CharSequence[].class};
declaringClass.getDeclaredMethod("doit", types);
I wonder if there's already something allowing me to write just
Method m = getMethod(declaringClass, "doit", 43, 44, "hello");
I wonder if somebody did this already, as the JLS is a bit complicated in this respect.
Actually, behaving exactly like the compiler is impossible as in Phase 1 the compiler accepts only methods matching without boxing and unboxing. When calling my hypothetical getMethod from above, the distinction between primitives and their wrappers is already lost (because of autoboxing when passing arguments via varargs). This problem seems to have no solution, so let's ignore it.
As suggested in an answer, BeanUtils.invokeMethod comes close. It's supposed to find the best match, whatever it means. Looking at MethodUtils.getMatchingAccessibleMethod shows that
it knows nothing about varargs
it's non-deterministic
so I'm looking for something better.

Alternatively you could use Bean Utils from Apache Commons:
public static Method getAccessibleMethod(
Class clazz,
String methodName,
Class[] parameterTypes)
According documentation:
Return an accessible method (that is, one that can be invoked via
reflection) with given name and parameters. If no such method can be
found, return null. This is just a convenient wrapper for
getAccessibleMethod(Method method).
Parameters:
clazz - get method from this class
methodName - get method with this name
parameterTypes - with these parameters types
The implementation get the accessible method and goes up in the hierarchy until it founds a match to it.
Direct to the Invocation
In order to perform invocation directly as you asked, you could use this method from the same API:
public static Object invokeExactMethod(
Object object,
String methodName,
Object[] args,
Class[] parameterTypes)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException
or even
public static Object invokeExactMethod(
Object object,
String methodName,
Object[] args)
throws
NoSuchMethodException,
IllegalAccessException,
InvocationTargetException
that first locates the method using getAccessibleMethod and later on invokes it.

The MethodHandle is a new way to get a overloaded method using a signature (java 7):
Example:
static class A {
public String get() {
return "A";
}
}
static class B extends A {
public String get() {
return "B";
}
}
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(String.class);
MethodHandle mh = lookup.findVirtual(A.class, "get", mt);;
System.out.println(mh.invoke(new B()));
}
Outputs:
B

Related

Create BiConsumer from LambdaMetafactory

I'm trying to dynamically create a method reference of type BiConsumer through LambdaMetafactory.
I was trying to apply two approaches found on https://www.cuba-platform.com/blog/think-twice-before-using-reflection/ - createVoidHandlerLambda and here Create BiConsumer as Field setter without reflection the Holger's answer.
However in both cases I'm having below error:
Exception in thread "main" java.lang.AbstractMethodError: Receiver class org.home.ref.App$$Lambda$15/0x0000000800066040 does not define or inherit an implementation of the resolved method abstract accept(Ljava/lang/Object;Ljava/lang/Object;)V of interface java.util.function.BiConsumer.
at org.home.ref.App.main(App.java:20)
My code is something like this:
public class App {
public static void main(String[] args) throws Throwable {
MyClass myClass = new MyClass();
BiConsumer<MyClass, Boolean> setValid = MyClass::setValid;
setValid.accept(myClass, true);
BiConsumer<MyClass, Boolean> mappingMethodReferences = createHandlerLambda(MyClass.class);
mappingMethodReferences.accept(myClass, true);
}
#SuppressWarnings("unchecked")
public static BiConsumer<MyClass, Boolean> createHandlerLambda(Class<?> classType) throws Throwable {
Method method = classType.getMethod("setValid", boolean.class);
MethodHandles.Lookup caller = MethodHandles.lookup();
CallSite site = LambdaMetafactory.metafactory(caller,
"accept",
MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class, MyClass.class, boolean.class),
caller.findVirtual(classType, method.getName(),
MethodType.methodType(void.class, method.getParameterTypes()[0])),
MethodType.methodType(void.class, classType, method.getParameterTypes()[0]));
MethodHandle factory = site.getTarget();
return (BiConsumer<MyClass, Boolean>) factory.invoke();
}
public static <C, V> BiConsumer<C, V> createSetter(Class<?> classType) throws Throwable {
Field field = classType.getDeclaredField("valid");
MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodHandle setter = lookup.unreflectSetter(field);
final CallSite site = LambdaMetafactory.metafactory(lookup,
"accept", MethodType.methodType(BiConsumer.class, MethodHandle.class),
setter.type().erase(), MethodHandles.exactInvoker(setter.type()), setter.type());
return (BiConsumer<C, V>)site.getTarget().invokeExact(setter);
}
}
Where MyClass looks like this:
public class MyClass {
public boolean valid;
public void setValid(boolean valid) {
this.valid = valid;
System.out.println("Called setValid");
}
}
I will appreciate for help with this one.
EDIT #1.
After consulting #Holger I've modified createSetter method to:
#SuppressWarnings("unchecked")
public static <C, V> BiConsumer<C, V> createSetter(Class<?> classType) throws Throwable {
Field field = classType.getDeclaredField("valid");
MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodHandle setter = lookup.unreflectSetter(field);
MethodType type = setter.type();
if(field.getType().isPrimitive())
type = type.wrap().changeReturnType(void.class);
final CallSite site = LambdaMetafactory.metafactory(lookup,
"accept", MethodType.methodType(BiConsumer.class, MethodHandle.class),
type.erase(), MethodHandles.exactInvoker(setter.type()), type);
return (BiConsumer<C, V>)site.getTarget().invokeExact(setter);
}
Now this method does not throw the initial Exception althoug it seems that calling accept on this method reference has no effect. I do not see "Called setValid" in logs for this call. Only for MyClass::setValid;
Note that your use of getMethod and caller.findVirtual(…) for the same method is redundant. If your starting point is a Method, you may use unreflect, e.g.
Method method = classType.getMethod("setValid", boolean.class);
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodHandle target = caller.unreflect(method);
This might be useful when you discover methods dynamically and/or are looking for other artifacts like annotations in the process. Otherwise, just getting the MethodHandle via findVirtual is enough.
Then, you have to understand the three different function types:
The target method handle has a specific type which is given implicitly when passing the method handle to the factory. In your case, it is (MyClass,boolean) → void
The generic function type associated with the intended result type
BiConsumer<MyClass, Boolean>, which is (MyClass,Boolean) → void
The erased type of the BiConsumer interface, which is (Object,Object) → void
Only specifying all three types correctly tells the factory that it must implement the method
void accept(Object,Object) with code which will cast the first argument to MyClass and the second to Boolean, followed by unwrapping the second argument to boolean, to eventually invoke the target method.
We could specify the types explicitly, but to make the code as reusable as possible, we can call type() on the target, followed by using adapter methods.
wrap() will convert all primitive types to their wrapper type. Unfortunately, this also implies converting the return type to Void, so we have to set it back to void again.
This gives us the instantiatedMethodType parameter. (Compare with the documentation)
erase() will convert all reference types to Object but leave all primitive types as-is. So applying it to the instantiatedMethodType gives us the erased type.
It depends on the particular target interface whether this simple transformation is sufficient. For the interfaces in java.util.function, it is.
Another point to raise the reusability is to use an actual type parameter for the method receiver class, as we get the class as parameter anyway:
public static <T>
BiConsumer<T, Boolean> createHandlerLambda(Class<T> classType) throws Throwable {
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodHandle target = caller.findVirtual(classType, "setValid",
MethodType.methodType(void.class, boolean.class));
MethodType instantiated = target.type().wrap().changeReturnType(void.class);
CallSite site = LambdaMetafactory.metafactory(caller,
"accept", MethodType.methodType(BiConsumer.class),
instantiated.erase(), target, instantiated);
return (BiConsumer<T, Boolean>)site.getTarget().invoke();
}

Different return type for the same method

i need to implement the newInstance method in order to make this code to work:
protected IDatabase createDatabase() throws Exception{
return newInstance(CLASS_NAME_DATABASE);
}
protected IDataLoader createDataLoader() throws Exception{
return newInstance(CLASS_NAME_DATA_LOADER);
}
I'm not allowed to touch this code, but when i try to implement the newInstance as Object it means i need to cast the newInstance in the code above you. Is there a way for me to implement newInstance without changing the code?
Thanks!
If the parameter to newInstance were a Class object, or something else with a generic type parameter, you could do the following, which would avoid needing to cast the return value, and be type-safe:
protected <T> T newInstance(Class<T> klass) throws Exception {
return klass.newInstance();
}
(Note: klass.newInstance() is the reflection API method, not the same as the method being defined, despite the same name.)
However, you can use generics no matter what sort of parameters newInstance takes:
#SuppressWarnings("unchecked")
protected <T> T newInstance(String className) throws Exception {
return (T)Class.forName(className).newInstance();
}
This is a bit dirty, because it completely eliminates compile-time error checking on the type of the return value. The compiler will allow IDataLoader x = newInstance(CLASS_NAME_DATA_LOADER); but will just as happily allow int x = newInstance(CLASS_NAME_DATA_LOADER); (which actually casts it to an Integer then unboxes it).
However, manually casting an Object return value would also not be checked at compile time, so using generics here is probably still an improvement since it reduces the number of times you have to write each type.

Java reflection for private static method with parameters

I have a problem using the invoke method in java.
I have a method to use to provide me a Method object and it looks like:
public static Method provideMethod(String methodName, Class targetClass) throws NoSuchMethodException {
Method method = targetClass.getDeclaredMethod(methodName,null);
//Set accessible provide a way to access private methods too
method.setAccessible(true);
return method;
}
Ok this method works perfectly when I'm trying to access methods, from any context (static, or non static), that have no arguments.
Now the problem is that I can't call invoke and pass arguments to a method that have arguments, for instance:
I have the following method :
private static boolean createDirectory(String path, String fileName) {
...
}
And I want to invoke it like this:
Boolean created = (Boolean) DataUtils.provideMethod("createDirectory", FileUtils.class).
invoke(null, String.class, String.class);
But I'm getting java.lang.NoSuchMethodException: createDirectory [].
Does somebody knows how can I invoke a private static method that have parameters ?
And, how can I pass values to that methods arguments?
Thanks,
Arkde
You're explicitly calling a reflection method which looks for a method declared with the given parameter types - but you're not providing any parameter types.
If you want to find any method with the given name, use getDeclaredMethods() and just filter by name... but then when you call invoke, you need to provide the string values, not the parameter types.
Alternatively, change your provideMethod call to also accept the parameter types, so you can use:
DataUtils.provideMethod("createDirectory", FileUtils.class,
String.class, String.class)
.invoke(null, "foo", "bar")
You're specifically only looking up methods with no arguments when you call
Method method = targetClass.getDeclaredMethod(methodName,null)
In order to find the createDirectory method, you'd need to call
targetClass.getDeclaredMethod("createDirectory", String.class, String.class)
but at present your provideMethod method has no way of doing this.
I would suggest that you change the signature of provideMethod so that it allows the caller to pass in the classes of the arguments that they're looking for, like so:
public static Method provideMethod(String methodName, Class targetClass, Class... parameterTypes) throws NoSuchMethodException {
Method method = targetClass.getDeclaredMethod(methodName, parameterTypes);
//Set accessible provide a way to access private methods too
method.setAccessible(true);
return method;
}
Change this
Method method = targetClass.getDeclaredMethod(methodName, null);
to something like that
Method method = targetClass.getDeclaredMethod(methodName, Class<?>... parameterTypes);
and your provideMethod accordingly.

Combining Java generics and reflection to avoid casting

I have some code like this:
Object doMethod(Method m, Object... args) throws Exception {
Object obj = m.getDeclaringClass().getConstructor().newInstance();
return m.invoke(obj, args);
}
The code I use is a little more complex, but that's the idea of it. To invoke doMethod I do something like this:
Method m = MyClass.class.getMethod("myMethod", String.class);
String result = (String)doMethod(m, "Hello");
This works just fine for me (variable number of arguments and all). The thing that irks me is the necessary cast to String in the caller. Since myMethod declares that it returns a String, I'd like doMethod to be smart enough to change its return type to also be String. Is there some way of using Java generics to accomplish something like this?
String result = doMethod(m, "Hello");
int result2 = doMethod(m2, "other", "args");
Sure,
#SuppressWarnings("unchecked")
<T> T doMethod(Method m, Class<T> returnType, Object Args ...) {
Object obj = m.getDeclaringClass().getConstructor().newInstance();
return (T) m.invoke(obj, args);
}
String result = doMethod(m, m.getReturnType(), "Hello");
One is idly curious about the architecture that calls for such a thing to be done, but that's well out of scope :)
If you don't like that you can also leave off the binding of returnType and the compiler will automatically cast it to whatever you're assigning the return type to. e.g., this is legal:
#SuppressWarnings("unchecked")
<T> T doMethod(Method m, Object Args ...) {
Object obj = m.getDeclaringClass().getConstructor().newInstance();
return (T) m.invoke(obj, args);
}
The cast will be to whatever you are attempting to assign it to, but I think most people would consider it suspect.
I wish that Method had been parameterized to capture the return type. You could always do that yourself by wrapping Method with your own MethodEx... Doing so would allow you to provide some pretty nice facades too...
public class MethodEx<T> {
private final Method _method;
private final Class<T> _returnType;
public MethodEx(Method method, Class<T> returnType) {
_method = method;
_returnType = returnType;
}
public T invoke(Object object, Object... args) throws InvocationTargetException {
try {
return _returnType.cast(_method.invoke(object, args));
}
// good opportunity to hide/wrap other exceptions if your
// usecases don't really encounter them
}
}
This is just a starting point -- you can have factory methods on MethodEx that does a lot of up-front validation to make sure method is public, etc.
Finally, if you are caching the Method instances etc and dealing with dynamically loaded classes, this would also be a good opportunity to defensively introduce weak references (to the method and the return type) so you don't have to be as careful about pegging entire classloaders throughout your code.
You could try
public <T> T doMethod(Method m, Class<T> clazz, Object... args);
Although it moves the cast to the routine itself. In general what you're trying to do doesn't sound like good practice. Reflection itself incurs some performance overhead, but perhaps that not of concern?

Type-safe method reflection in Java

Is any practical way to reference a method on a class in a type-safe manner? A basic example is if I wanted to create something like the following utility function:
public Result validateField(Object data, String fieldName,
ValidationOptions options) { ... }
In order to call it, I would have to do:
validateField(data, "phoneNumber", options);
Which forces me to either use a magic string, or declare a constant somewhere with that string.
I'm pretty sure there's no way to get around that with the stock Java language, but is there some kind of (production grade) pre-compiler or alternative compiler that may offer a work around? (similar to how AspectJ extends the Java language) It would be nice to do something like the following instead:
public Result validateField(Object data, Method method,
ValidationOptions options) { ... }
And call it with:
validateField(data, Person.phoneNumber.getter, options);
As others mention, there is no real way to do this... and I've not seen a precompiler that supports it. The syntax would be interesting, to say the least. Even in your example, it could only cover a small subset of the potential reflective possibilities that a user might want to do since it won't handle non-standard accessors or methods that take arguments, etc..
Even if it's impossible to check at compile time, if you want bad code to fail as soon as possible then one approach is to resolve referenced Method objects at class initialization time.
Imagine you have a utility method for looking up Method objects that maybe throws error or runtime exception:
public static Method lookupMethod( Class c, String name, Class... args ) {
// do the lookup or throw an unchecked exception of some kind with a really
// good error message
}
Then in your classes, have constants to preresolve the methods you will use:
public class MyClass {
private static final Method GET_PHONE_NUM = MyUtils.lookupMethod( PhoneNumber.class, "getPhoneNumber" );
....
public void someMethod() {
validateField(data, GET_PHONE_NUM, options);
}
}
At least then it will fail as soon as MyClass is loaded the first time.
I use reflection a lot, especially bean property reflection and I've just gotten used to late exceptions at runtime. But that style of bean code tends to error late for all kinds of other reasons, being very dynamic and all. For something in between, the above would help.
There isn't anything in the language yet - but part of the closures proposal for Java 7 includes method literals, I believe.
I don't have any suggestions beyond that, I'm afraid.
Check out https://proxetta.jodd.org/refs/methref. It uses the Jodd proxy library (Proxetta) to proxy your type. Not sure about its performance characteristics, but it does provide type safety.
An example: Suppose Str.class has method .boo(), and you want to get its name as the string "boo":
String methodName = Methref.of(Str.class).name(Str::boo);
There's more to the API than the example above: https://oblac.github.io/jodd-site/javadoc/jodd/methref/Methref.html
Is any practical way to reference a method on a class in a type-safe manner?
First of all, reflection is type-safe. It is just that it is dynamically typed, not statically typed.
So, assuming that you want a statically typed equivalent of reflection, the theoretical answer is that it is impossible. Consider this:
Method m;
if (arbitraryFunction(obj)) {
m = obj.getClass().getDeclaredMethod("foo", ...);
} else {
m = obj.getClass().getDeclaredMethod("bar", ...);
}
Can we do this so that that runtime type exceptions cannot happen? In general NO, since this would entail proving that arbitraryFunction(obj) terminates. (This is equivalent to the Halting Problem, which is proven to be unsolvable in general, and is intractable using state-of-the-art theorem proving technology ... AFAIK.)
And I think that this road-block would apply to any approach where you could inject arbitrary Java code into the logic that is used to reflectively select a method from an object's class.
To my mind, the only moderately practical approach at the moment would be to replace the reflective code with something that generates and compiles Java source code. If this process occurs before you "run" the application, you've satisfied the requirement for static type-safety.
I was more asking about reflection in which the result is always the same. I.E. Person.class.getMethod("getPhoneNumber", null) would always return the same method and it's entirely possible to resolve it at compile time.
What happens if after compiling the class containing this code, you change Person to remove the getPhoneNumber method?
The only way you can be sure that you can resolve getPhoneNumber reflectively is if you can somehow prevent Person from being changed. But you can't do that in Java. Runtime binding of classes is a fundamental part of the language.
(For record, if you did that for a method that you called non-reflectively, you would get an IncompatibleClassChangeError of some kind when the two classes were loaded ...)
It has been pointed out that in Java 8 and later you could declare your validator something like this:
public Result validateField(Object data,
SomeFunctionalInterface function,
ValidationOptions options) { ... }
where SomeFunctionalInterface corresponds to the (loosely speaking) common signature of the methods you are validating.
Then you can call it with a method reference; e.g.
validateField(data, SomeClass::someMethod, options)
This is approach is statically type-safe. You will get a compilation error if SomeClass doesn't have someMethod or if it doesn't conform to SomeFunctionalInterface.
But you can't use a string to denote the method name. Looking up a method by name would entail either reflection ... or something else that side-steps static (i.e. compile time / load time) type safety.
Java misses the syntax sugar to do something as nice as Person.phoneNumber.getter. But if Person is an interface, you could record the getter method using a dynamic proxy. You could record methods on non-final classes as well using CGLib, the same way Mockito does it.
MethodSelector<Person> selector = new MethodSelector<Person>(Person.class);
selector.select().getPhoneNumber();
validateField(data, selector.getMethod(), options);
Code for MethodSelector: https://gist.github.com/stijnvanbael/5965609
Inspired by mocking frameworks, we could dream up the following syntax:
validator.validateField(data, options).getPhoneNumber();
Result validationResult = validator.getResult();
The trick is the generic declaration:
class Validator {
public <T> T validateField(T data, options) {...}
}
Now the return type of the method is the same as your data object's type and you can use code completion (and static checking) to access all the methods, including the getter methods.
As a downside, the code isn't quite intuitive to read, since the call to the getter doesn't actually get anything, but instead instructs the validator to validate the field.
Another possible option would be to annotate the fields in your data class:
class FooData {
#Validate(new ValidationOptions(...))
private PhoneNumber phoneNumber;
}
And then just call:
FooData data;
validator.validate(data);
to validate all fields according to the annotated options.
The framework picklock lets you do the following:
class Data {
private PhoneNumber phoneNumber;
}
interface OpenData {
PhoneNumber getPhoneNumber(); //is mapped to the field phoneNumber
}
Object data = new Data();
PhoneNumber number = ObjectAccess
.unlock(data)
.features(OpenData.class)
.getPhoneNumber();
This works in a similar way setters and private methods. Of course, this is only a wrapper for reflection, but the exception does not occur at unlocking time not at call time. If you need it at build time, you could write a unit test with:
assertThat(Data.class, providesFeaturesOf(OpenData.class));
I found a way to get the Method instance using Lambdas. It works only on interface methods though currently.
It works using net.jodah:typetools which is a very lightweight library.
https://github.com/jhalterman/typetools
public final class MethodResolver {
private interface Invocable<I> {
void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable;
}
interface ZeroParameters<I, R> extends Invocable<I> {
R invoke(I instance) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance);
}
}
public static <I, R> Method toMethod0(ZeroParameters<I, R> call) {
return toMethod(ZeroParameters.class, call, 1);
}
interface OneParameters<I, P1, R> extends Invocable<I> {
R invoke(I instance, P1 p1) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance, param(parameterTypes[1]));
}
}
public static <I, P1, R> Method toMethod1(OneParameters<I, P1, R> call) {
return toMethod(OneParameters.class, call, 2);
}
interface TwoParameters<I, P1, P2, R> extends Invocable<I> {
R invoke(I instance, P1 p1, P2 p2) throws Throwable;
#Override
default void invokeWithParams(I instance, Class<?>[] parameterTypes) throws Throwable {
invoke(instance, param(parameterTypes[1]), param(parameterTypes[2]));
}
}
public static <I, P1, P2, R> Method toMethod2(TwoParameters<I, P1, P2, R> call) {
return toMethod(TwoParameters.class, call, 3);
}
private static final Map<Class<?>, Object> parameterMap = new HashMap<>();
static {
parameterMap.put(Boolean.class, false);
parameterMap.put(Byte.class, (byte) 0);
parameterMap.put(Short.class, (short) 0);
parameterMap.put(Integer.class, 0);
parameterMap.put(Long.class, (long) 0);
parameterMap.put(Float.class, (float) 0);
parameterMap.put(Double.class, (double) 0);
}
#SuppressWarnings("unchecked")
private static <T> T param(Class<?> type) {
return (T) parameterMap.get(type);
}
private static <I> Method toMethod(Class<?> callType, Invocable<I> call, int responseTypeIndex) {
Class<?>[] typeData = TypeResolver.resolveRawArguments(callType, call.getClass());
Class<?> instanceClass = typeData[0];
Class<?> responseType = responseTypeIndex != -1 ? typeData[responseTypeIndex] : Void.class;
AtomicReference<Method> ref = new AtomicReference<>();
I instance = createProxy(instanceClass, responseType, ref);
try {
call.invokeWithParams(instance, typeData);
} catch (final Throwable e) {
throw new IllegalStateException("Failed to call no-op proxy", e);
}
return ref.get();
}
#SuppressWarnings("unchecked")
private static <I> I createProxy(Class<?> instanceClass, Class<?> responseType,
AtomicReference<Method> ref) {
return (I) Proxy.newProxyInstance(MethodResolver.class.getClassLoader(),
new Class[] {instanceClass},
(proxy, method, args) -> {
ref.set(method);
return parameterMap.get(responseType);
});
}
}
Usage:
Method method = MethodResolver.toMethod2(SomeIFace::foobar);
System.out.println(method); // public abstract example.Result example.SomeIFace.foobar(java.lang.String,boolean)
Method get = MethodResolver.<Supplier, Object>toMethod0(Supplier::get);
System.out.println(get); // public abstract java.lang.Object java.util.function.Supplier.get()
Method accept = MethodResolver.<IntFunction, Integer, Object>toMethod1(IntFunction::apply);
System.out.println(accept); // public abstract java.lang.Object java.util.function.IntFunction.apply(int)
Method apply = MethodResolver.<BiFunction, Object, Object, Object>toMethod2(BiFunction::apply);
System.out.println(apply); // public abstract java.lang.Object java.util.function.BiFunction.apply(java.lang.Object,java.lang.Object)
Unfortunately you have to create a new interface and method based on the parameter count and whether the method returns void or not.
However, if you have a somewhat fixed/limited method signature/parameter types, then this becomes quite handy.

Categories