JDK-8141122 : IllegalAccessException using method reference to package-private class via publ
  • Type: Bug
  • Component: tools
  • Affected Version: 8u66
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86_64
  • Submitted: 2015-10-30
  • Updated: 2016-04-20
  • Resolved: 2016-01-21
Related Reports
Duplicate :  
Description
FULL PRODUCT VERSION :
openjdk version "1.8.0-jdk8u76-b00"
OpenJDK Runtime Environment (build 1.8.0-jdk8u76-b00-20151028)
OpenJDK 64-Bit Server VM (build 25.66-b20151028, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux (hostname) 3.13.0-24-generic #46-Ubuntu SMP Thu Apr 10 19:11:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
I have a package-private class "A" and a public class "B" that extends it. Class A has a public static method "print" that I want to access via a method pointer from class "C", which is in a different package. I use "B::print" as the method pointer, which compiles fine, but I get an IllegalAccessException when I run the code. It looks like the compiler is generating a class file that references A.print() instead of B.print(). The Eclipse compiler (where I originally filed this bug) generates a class file that correctly references B.print(), but the runtime error still occurs.

Jesper Moller provided some good information in the Eclipse bug I filed:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=480930#c4

I was able to work around the issue by making the base class public, but I'd rather leave it package-private, if possible.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Enter the attached code and try to execute the example.b.C class.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The generated class file should contain a reference to the example.a.B.print(int) method. The application should print out a list of integers between 0 and 9.
ACTUAL -
The generated class file contains a reference to the example.a.A.print(int) method. Execution fails with the attached error message.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
Exception in thread "main" java.lang.IllegalAccessError: tried to access class example.a.A from class example.b.C
	at example.b.C.lambda$main$0(C.java:11)
	at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110)
	at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:557)
	at example.b.C.main(C.java:11)


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// example/a/B.java

package example.a;

abstract class A
{
   public static void print(int value)
   {
      System.out.println(value);
   }
}

public class B extends A
{
   // No additional functionality.
}

// example/b/C.java

package example.b;

import java.util.stream.IntStream;

import example.a.B;

public class C
{
   public static void main(String[] args)
   {
      IntStream.range(0, 10).forEach(B::print);

      // This line executes fine.      
//      IntStream.range(0, 10).forEach(value -> {B.print(value);});
   }
}

// Jesper Moller provided this alternate version of C.java in the Eclipse bug I filed:

package example.b;

import java.lang.invoke.*;

import example.c.B;

public class C {
   public static void main(String[] args) throws Throwable {
     MethodHandles.Lookup me = MethodHandles.lookup();

     MethodType t = MethodType.methodType(void.class);
     MethodType rt = MethodType.methodType(Runnable.class);
     MethodHandle b_print = me.findStatic(B.class, "print", t); // becomes A::print
     CallSite site = LambdaMetafactory.metafactory(me, "run", rt, t, b_print, t);
     MethodHandle factory = site.getTarget();
     Runnable b_print_asRunnable = (Runnable) factory.invoke();
   }
}

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

CUSTOMER SUBMITTED WORKAROUND :
I reluctantly made the base class public to work around this issue. I'd rather not expose the base class, though.


Comments
JDK-8068254 was backported to 8u and will be released as part of 8u76
22-01-2016

This issue is a duplicate of JDK-8068254. Provided reproducer application passes with JDK-8068254 fix applied.
21-01-2016

The bug report has been raised for OpenJDK , but it is reproducible on Oracle JDK also. Attached Test case could only be reproduced on Linux: JDK 8u66 - Fail JDK 9ea - Pass On Windows JDK 8u66, the test passes. Actual output: ---------------------------------------------------------------------------------------------- java example.b.C Exception in thread "main" java.lang.IllegalAccessError: tried to access class example.a.A from class example.b.C at example.b.C.lambda$main$0(C.java:9) at java.util.stream.Streams$RangeIntSpliterator.forEachRemaining(Streams.java:110) at java.util.stream.IntPipeline$Head.forEach(IntPipeline.java:557) at example.b.C.main(C.java:9) Moving across to dev-team for evaluation.
02-11-2015