JSR 335 spec, chapter "15.28.2 Run-time Evaluation of Method References" contains following assertion:
If the method reference has the form ExpressionName :: NonWildTypeArgumentsopt Identifier or Primary :: NonWildTypeArgumentsopt Identifier, the body of the invocation method has the effect of invoking the compile-time declaration of the method reference, as described in 15.12.4.3, 15.12.4.4, 15.12.4.5.[jsr335-15.28.2-41]
This assertions refers to chapter "15.12.4.3. Check Accessibility of Type and Method" which contains following assertions:
Let C be the class containing the method invocation, and let T be the qualifying type of the method invocation (��13.1), and let m be the name of the method as determined at compile-time (��15.12.3).
...
If T is in a different package than C, and T is protected, then T is accessible if and only if C is a subclass of T.
...
According to these assertions MethodInvoker.invoke should succeed, provided, the class files resulted form following sources compilation are supplied at run-time:
MethodInvoker.java:
import anotherpkg.MethodSupplierOuter;
import anotherpkg.MethodSupplierFactory;
public class MethodInvoker extends MethodSupplierOuter.MethodSupplier {
public static void invoke() throws Exception {
MethodInvoker ms = (MethodInvoker)MethodSupplierFactory.create();
MyFunctionalInterface fi = ms::m;
fi.invokeMethodReference();
}
}
MethodSupplierOuter.java:
package anotherpkg;
public class MethodSupplierOuter {
protected static class MethodSupplier {
public void m() {
System.out.println("bad");
}
}
}
MethodSupplierFactory.java:
package anotherpkg;
public class MethodSupplierFactory {
public static Object create() throws Exception {
return Class.forName("MethodInvoker").newInstance();
}
}
but exception is thrown instead resulting in following output:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:491)
at Test.main(Test.java:7)
Caused by: java.lang.IncompatibleClassChangeError
at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:383)
at MethodInvoker.invoke(MethodInvoker.java:7)
... 5 more
Caused by: java.lang.IllegalAccessException: symbolic reference class is not public: class anotherpkg.MethodSupplierOuter$MethodSupplier, from MethodInvoker
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:744)
at java.lang.invoke.MethodHandles$Lookup.checkSymbolicClass(MethodHandles.java:1026)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1017)
at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1284)
at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:381)
... 6 more
This was reproduced on b100, platform: Windows7x64.
The minimized test is attached.
The steps to reproduce the error are below, they should be performed in exactly specified order:
1) compile Test.java from archive;
2) compile sources from "anotherpkg" package from archive;
3) compile MethodInvoker.java from archive;
4) compile bad/MethodSupplier.java from archive;
5) run Test.main.