JDK-8138667 : java.lang.IllegalAccessError: tried to access method (for a protected method)
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8u60
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2015-09-22
  • Updated: 2019-09-11
  • Resolved: 2016-09-13
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 9
9 b137Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)


FULL OS VERSION :
Mac OS X 10.9.5
Windows 7

A DESCRIPTION OF THE PROBLEM :
A lambda nested in an anonymous class cannot call a protected method inherited by the class surrounding the anonymous class.

The compiler accepts this code but running it produces a java.lang.IllegalAccessError.

THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Yes

THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Yes

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the test classes and run class bbb.Test

EXPECTED VERSUS ACTUAL BEHAVIOR :
Expected:

The method aaa.AbstractClass#myDo() is called and prints "It works" to System.out

Actual:

A BootstrapMethodError is thrown caused by an IllegalAccessError
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access method aaa.AbstractClass.myDo()V from class bbb.Test$1
	at bbb.Test$1.call(Test.java:22)
	at bbb.Test.doTest(Test.java:26)
	at bbb.Test.main(Test.java:31)
Caused by: java.lang.IllegalAccessError: tried to access method aaa.AbstractClass.myDo()V from class bbb.Test$1
	at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
	at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
	at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987)
	at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1390)
	at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1746)
	at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:477)
	... 3 more


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
package aaa;

/**
 * <hr>
 * <p>User: mathias</p>
 * <p>Date: 22.09.15</p>
 * <p>Time: 15:37</p>
 */
public abstract class AbstractClass {
    protected final void myDo() {
        System.err.println("It works!");
    }
}
----------------------------------------------------
package bbb;

import aaa.AbstractClass;

import java.util.concurrent.Callable;

/**
 * <hr>
 * <p>User: mathias</p>
 * <p>Date: 22.09.15</p>
 * <p>Time: 15:39</p>
 */
public final class Test extends AbstractClass {
    public Test() {

    }

    public void doTest() throws Exception {
        new Callable<Void>() {
            @Override
            public Void call() throws Exception {
                final Runnable r = Test.this::myDo;
                r.run();
                return null;
            }
        }.call();
    }

    public static void main(String[] args) throws Exception {
        final Test test = new Test();
        test.doTest();
    }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
1. Replace the anonymous class with a lambda expression
2. Replace the lamba expression with an anonymous class

BUT: Both workarounds do not address the initial problem, that the unmodified code is accepted by the compiler but rejected at runtime!


Comments
The exception is coming from the wrap_invokedynamic_exception() in linkResolver.cpp: THROW_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), nested_exception) This was found by running the test with the -XX:+TraceExceptions option. Attaching the javap -verbose output for the original (javap_org.txt) and the modified (javap_workaround.txt) Test. There's the following access$000 static method with the workaround but not in the original Test: static void access$000(bbb.Test); descriptor: (Lbbb/Test;)V flags: ACC_STATIC, ACC_SYNTHETIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokevirtual #1 // Method myDo:()V 4: return
17-06-2016

This problem is reproducible with the latest jdk8u as well as jdk9. A workaround is in the doTest() method, replace the following: final Runnable r = Test.this::myDo; with a lambda expression: final Runnable r = ()->myDo();
17-06-2016