techjourneyman
techjourneyman

Reputation: 1813

Functional interface to pass any method as parameter in Java

I am trying to write a method that takes in 2 parameters - a class reference, and a reference of a method in that class. The return type of the method itself should be whatever that class's method return type is. For example:

public <T> T myMethod (Class<?> c, <reference to a method m in class c>), where m returns something of type <T>.

That is, in my code I should be able to call the above method as:

myMethod (SomeClass.class, x -> x.someMethod(param1, param2))

Note that SomeClass can be any class, and someMethod can be any method in that class with any number of parameters.

I am reasonably sure this is possible using lambda and functional interface in Java 8, but not entire clear on how to put it.

Upvotes: 1

Views: 12321

Answers (2)

Andreas
Andreas

Reputation: 159096

The functional interface method needs to take one argument of the same type as the named class c, so you need to define a generic type for that class, lets call it C.

The functional interface method needs to return a value of type T, but lets rename it R to represent the return type.

This means that your function interface can be: Function<C, R>

Your full method declaration is then:

public <C, R> R myMethod(Class<? extends C> clazz, Function<C, R> method)

It can be called exactly like you showed.

Demo

public class Test {
    public static void main(String[] args) throws Exception {
        Test t = new Test();
        String param1 = "Foo", param2 = "Bar";

        String result = t.myMethod(SomeClass.class, x -> x.someMethod(param1, param2));

        System.out.println(result);
    }
    public <C, R> R myMethod(Class<? extends C> clazz, Function<C, R> method) throws Exception {
        C obj = clazz.getConstructor().newInstance();
        return method.apply(obj);
    }
}

class SomeClass {
    public SomeClass() {}
    public String someMethod(String param1, String param2) {
        return param1 + " + " + param2 + ": " + this;
    }
}

Output

Foo + Bar: test.SomeClass@5594a1b5

Upvotes: 10

Frontear
Frontear

Reputation: 1261

What you are trying to do isn't immediately possible. Meaning, you can't reference a method without having a direct reflective access to it.

Effectively, myMethod(MyClass.class, myClass -> myClass.Hello) is definitely not a good solution to anything. Think about it, where would you need this? If the method was static, you could invoke it anyways, and if it wasn't, you'd only need an instance.

What you can do, however, is find your method and invoke it through the reflection api:

public Object myMethod(Class<?> clazz) {
    return clazz.getDeclaredMethod("name_of_method", ... /*Any parameters*/).invoke(/*params*/);
}

Upvotes: 0

Related Questions