Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Is it possible to convert a method reference (e.g. SomeClass::someMethod) to a MethodHandle instance? I want the benefits of compile-time checking (ensuring that the class and method exists) as well as the ability to introspect the method using the MethodHandle API.

Use-case: I've got code that needs to execute if and only if the request was not triggered by a specific method (to avoid endless recursion). I want a compile-time check to ensure the class/method exists but a runtime check to compare the caller to the method.

So to recap: Is it possible to convert a method reference to a MethodHandle?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
185 views
Welcome To Ask or Share your Answers For Others

1 Answer

Well, if you can afford the additional overhead and security implications, you can use a Serializable functional interface and decode the serialized form of the method reference instance to find the target like demonstrated in this answer or brought up again with this question and its answers.

However, you should really rethink your software design. “Avoiding endless recursion” shouldn’t be fixed by decoding some kind of parameter object, especially not if your assumption is, that this actual argument value represents the caller of your method. How would you ever enforce this strange relationship?

Even a simple code change like referencing a method which delegates to the other method would break your check. Here is a simple example showing the subtle problems with your approach:

public class SimpleTest {
    public static void main(String... arg) {
        run(SimpleTest::process);
    }
    static void run(BiConsumer<Object,Object> c) {
        c.accept("foo", "bar");
    }
    static void process(Object... arg) {
        Thread.dumpStack();
    }
}

When running this program it will print something like:

java.lang.Exception: Stack trace
    at java.lang.Thread.dumpStack(Thread.java:1329)
    at SimpleTest.process(SimpleTest.java:16)
    at SimpleTest.lambda$MR$main$process$a9318f35$1(SimpleTest.java:10)
    at SimpleTest$$Lambda$1/26852690.accept(Unknown Source)
    at SimpleTest.run(SimpleTest.java:13)
    at SimpleTest.main(SimpleTest.java:10)

showing that the method reference within the generated instance is not the expected SimpleTest::process but instead SimpleTest::lambda$MR$main$process$a9318f35$1 which will eventually invoke process. The reason is that some operations (here varargs processing) are not performed by the generated interface instance but a synthetic method instead, just like you had written run((a,b)-> SimpleTest.process(a,b)). The only difference is the name of the synthetic method.

You shouldn’t design software relying on such fragile introspection. If you want to avoid recursion, a simple ThreadLocal flag telling whether you are already inside your specific method would do the job. But it might be worth asking yourself why your API is provoking endless recursion in the first place; there seems to be something fundamentally wrong…


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...