JDK-8022720 : private method should be accessible (nested classes)
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2013-08-09
  • Updated: 2014-09-24
  • Resolved: 2013-10-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b115Fixed
Related Reports
Blocks :  
Relates :  
Relates :  
Description
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 m is private, then m is accessible if and only if C is T, or C encloses T, or T encloses C, or T and C are both enclosed by a third class.
...

According to these assertions MethodInvoker.invoke should succeed for following three cases: 

case 1:
class MethodInvoker {
    public static void invoke() {
        MethodSupplier ms = new MethodSupplier();
        MyFunctionalInterface1 fi = ms::m;
        fi.invokeMethodReference();
    }
    static class MethodSupplier {
        private void m() {
            System.out.println("m");
        }    
    }
}

case 2:
class MethodSupplier {
    private void m() {
        System.out.println("m");
    }    
    static class MethodInvoker {
        public static void invoke() {
            MethodSupplier ms = new MethodSupplier();
            MyFunctionalInterface2 fi = ms::m;
            fi.invokeMethodReference();
        }
    }
}

case 3:
class ThirdClass {
    static class MethodSupplier {
        private void m() {
            System.out.println("m");
        }    
    }

    static class MethodInvoker {
        public static void invoke() {
            MethodSupplier ms = new MethodSupplier();
            MyFunctionalInterface3 fi = ms::m;
            fi.invokeMethodReference();
        }
    }
}

but all of these 3 cases fail with following stack traces correspondingly:

case1:
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 Test1.main(Test1.java:20)
Caused by: java.lang.IncompatibleClassChangeError
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:383)
	at MethodInvoker.invoke(Test1.java:8)
	... 5 more
Caused by: java.lang.IllegalAccessException: member is private: MethodInvoker$MethodSupplier.m()void/invokeSpecial, from MethodInvoker
	at java.lang.invoke.MemberName.makeAccessException(MemberName.java:744)
	at java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:1129)
	at java.lang.invoke.MethodHandles$Lookup.checkMethod(MethodHandles.java:1092)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:1203)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethod(MethodHandles.java:1193)
	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1285)
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:381)
	... 6 more

case 2:
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 Test2.main(Test2.java:21)
Caused by: java.lang.IncompatibleClassChangeError
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:383)
	at MethodSupplier$MethodInvoker.invoke(Test2.java:13)
	... 5 more
Caused by: java.lang.IllegalAccessException: member is private: MethodSupplier.m()void/invokeSpecial, from MethodSupplier$MethodInvoker
	at java.lang.invoke.MemberName.makeAccessException(MemberName.java:744)
	at java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:1129)
	at java.lang.invoke.MethodHandles$Lookup.checkMethod(MethodHandles.java:1092)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:1203)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethod(MethodHandles.java:1193)
	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1285)
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:381)
	... 6 more

case 3:
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 Test3.main(Test3.java:24)
Caused by: java.lang.IncompatibleClassChangeError
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:383)
	at ThirdClass$MethodInvoker.invoke(Test3.java:16)
	... 5 more
Caused by: java.lang.IllegalAccessException: member is private: ThirdClass$MethodSupplier.m()void/invokeSpecial, from ThirdClass$MethodInvoker
	at java.lang.invoke.MemberName.makeAccessException(MemberName.java:744)
	at java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:1129)
	at java.lang.invoke.MethodHandles$Lookup.checkMethod(MethodHandles.java:1092)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethodCommon(MethodHandles.java:1203)
	at java.lang.invoke.MethodHandles$Lookup.getDirectMethod(MethodHandles.java:1193)
	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1285)
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:381)
	... 6 more

This was reproduced on b100, platform: Windows7x64.

The minimized tests are attached in a single archive.

In order to reproduce case 1, 2 and 3 please run Test1.main, Test2.main and Test3.main from attached archive correspondingly.
Comments
Verified with b115.
08-11-2013

For method references, we address this kind of issue by converting the method reference into a lambda. Working on doing exactly that.
23-10-2013

Below tests failed for JDk8 b110 abd JCK8 b32: lang/LMBD/lmbd140/lmbd14003m0202/lmbd14003m0202_rt lang/LMBD/lmbd140/lmbd14003m1012/lmbd14003m1012_rt lang/LMBD/lmbd140/lmbd14004m1101/lmbd14004m1101_rt lang/LMBD/lmbd140/lmbd14005m2002/lmbd14005m2002_rt lang/LMBD/lmbd140/lmbd14005m5102/lmbd14005m5102_rt lang/LMBD/lmbd140/lmbd14006m2002/lmbd14006m2002_rt lang/LMBD/lmbd140/lmbd14007m2001/lmbd14007m2001_rt lang/LMBD/lmbd140/lmbd14007m31011/lmbd14007m31011_rt lang/LMBD/lmbd140/lmbd14008m51021/lmbd14008m51021_rt lang/LMBD/lmbd140/lmbd14009m0/lmbd14009m0_rt lang/LMBD/lmbd140/lmbd14009m022/lmbd14009m022_rt lang/LMBD/lmbd140/lmbd14009m04/lmbd14009m04_rt lang/LMBD/lmbd140/lmbd14009m111/lmbd14009m111_rt lang/LMBD/lmbd140/lmbd14009m133/lmbd14009m133_rt lang/LMBD/lmbd140/lmbd14010m0/lmbd14010m0_rt lang/LMBD/lmbd140/lmbd14010m04/lmbd14010m04_rt lang/LMBD/lmbd140/lmbd14010m13/lmbd14010m13_rt lang/LMBD/lmbd140/lmbd14011m0/lmbd14011m0_rt lang/LMBD/lmbd140/lmbd14011m022/lmbd14011m022_rt lang/LMBD/lmbd140/lmbd14011m04/lmbd14011m04_rt lang/LMBD/lmbd140/lmbd14011m111/lmbd14011m111_rt lang/LMBD/lmbd140/lmbd14011m133/lmbd14011m133_rt lang/LMBD/lmbd140/lmbd14012m151/lmbd14012m151_rt lang/LMBD/lmbd140/lmbd14007m0021/lmbd14007m0021_rt
14-10-2013

The JVM cannot directly support private nestmate access until JDK-8010319 is fixed. Until then, the javac compiler must continue to use Lower.accessName wrappers.
08-10-2013

lang/LMBD/lmbd140/lmbd14010m02/lmbd14010m02_rt lang/LMBD/lmbd140/lmbd14010m11/lmbd14010m11_rt lang/LMBD/lmbd142/lmbd14201m62/lmbd14201m62_rt
27-09-2013

Exceptions are in 292 code as is the bug title
26-09-2013

Following JCK8 Compiler Suite tests fail due to this issue: lang/LMBD/lmbd140/lmbd14009m0/lmbd14009m0.html lang/LMBD/lmbd140/lmbd14009m022/lmbd14009m022.html lang/LMBD/lmbd140/lmbd14009m04/lmbd14009m04.html lang/LMBD/lmbd140/lmbd14009m111/lmbd14009m111.html lang/LMBD/lmbd140/lmbd14009m133/lmbd14009m133.html lang/LMBD/lmbd140/lmbd14010m0/lmbd14010m0.html lang/LMBD/lmbd140/lmbd14010m02/lmbd14010m02.html lang/LMBD/lmbd140/lmbd14010m04/lmbd14010m04.html lang/LMBD/lmbd140/lmbd14010m11/lmbd14010m11.html lang/LMBD/lmbd140/lmbd14010m13/lmbd14010m13.html lang/LMBD/lmbd140/lmbd14011m0/lmbd14011m0.html lang/LMBD/lmbd140/lmbd14011m022/lmbd14011m022.html lang/LMBD/lmbd140/lmbd14011m04/lmbd14011m04.html lang/LMBD/lmbd140/lmbd14011m111/lmbd14011m111.html lang/LMBD/lmbd140/lmbd14011m133/lmbd14011m133.html lang/LMBD/lmbd140/lmbd14012m151/lmbd14012m151.html
03-09-2013

The JVM behavior is, unfortunately, correct, because we have not fixed the spec. problem JDK-8010319. The JVM is unfortunately forbidden to provide direct access to private members in the same nest. As has been the case since JDK 1.1, the javac compiler needs to create access wrappers to bridge from one class to another in the same class nest.
09-08-2013