The lookup factory methods of MethodHandles.Lookup perform access checking based on a provided "referenced class", 'refc'. However, the 'revealDirect' method checks access against the *declaring* class. As a result, a straightforward back-to-back findStatic/revealDirect can fail.
---
package p1;
class A {
public static void staticMethod() {}
public void instanceMethod() {}
}
---
package p1;
public class B extends A {}
---
package p2;
public class C extends p1.B {}
---
import java.lang.invoke.*;
public class Test {
public static void main(String... args) throws Exception {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.findStatic(p2.C.class, "staticMethod", MethodType.methodType(void.class));
System.out.println("mh: " + mh);
MethodHandleInfo mhi = lookup.revealDirect(mh);
System.out.println("mhi: " + mhi);
}
}
---
Program output:
mh: MethodHandle()void
Exception in thread "main" java.lang.IllegalArgumentException: java.lang.IllegalAccessException: class is not public: p1.A.staticMethod()void/invokeStatic, from Test (unnamed module @3834d63f)
at java.base/java.lang.invoke.MethodHandles$Lookup.revealDirect(MethodHandles.java:1835)
at Test.main(Test.java:10)
Caused by: java.lang.IllegalAccessException: class is not public: p1.A.staticMethod()void/invokeStatic, from Test (unnamed module @3834d63f)
at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:915)
at java.base/java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:2022)
at java.base/java.lang.invoke.MethodHandles$Lookup.revealDirect(MethodHandles.java:1832)
... 1 more
---
If I use 'findVirtual' to inspect 'instanceMethod' instead, there is no access checking error, although the result doesn't provide accurate information, apparently in an attempt to workaround the access checking problem:
mh: MethodHandle(C)void
mhi: invokeVirtual p1.B.instanceMethod:()void
(Note that p1.B is neither the declaring class nor the referenced class.)
---
This issue is closely tied to JDK-8068253: direct method handles ought to be preserving their referenced class rather than assuming the declaring class is sufficient.
Note that, because of this problem, LambdaMetafactory is unable to properly handle some inputs (such as for 'p2.C::staticMethod'), and as a workaround javac currently generates "bridge" lambda methods (see, e.g., JDK-8068254).