JDK-8038975 : Access control in enhanced for
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2014-04-01
  • Updated: 2014-07-29
  • Resolved: 2014-06-18
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 JDK 9
8u20 b20Fixed 9Fixed
Related Reports
Relates :  
Description
FULL PRODUCT VERSION :
javac 1.8.0

A DESCRIPTION OF THE PROBLEM :
The source code indicated below no longer compiles in jdk8, but jdk7u51 compiled successfully as expected.

The reason is a wrong accessibility check on the method Inner.iterator() inherited from Iterable.iterator().
As per JLS 6.6, Inner.iterator() is accessible from OuterImpl because:
1. Inner.iterator() is public;
2. Inner is accessible from OuterImpl because:
2a. Inner is protected and declared by Outer;
2b. OuterImpl is a subclass of Outer.

REGRESSION.  Last worked in version 7u51

ADDITIONAL REGRESSION INFORMATION: 
javac 1.7.0_51

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile with the two versions of javac and notice the difference. Note: specifying -source 7 with javac version 8 does not work.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The sources should compile normally.
ACTUAL -
The compilation fails with the following message:
error: iterator() in Iterable is defined in an inaccessible class or interface
            for (Something st : inner)
  where T is a type-variable:
    T extends Object declared in interface Iterable

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
// File a/Something.java
package a;
public class Something { }

// File a/Outer.java
package a;
public class Outer {
    protected abstract class Inner implements Iterable<Something> { }
}

// File b/Client.java
package b;
import a.*;
public class Client {
    private static class OuterImpl extends Outer {
        public void method(Inner inner) {
            for (Something st : inner)
                System.out.println(st); // or anything else
        }
    }
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Workaround 1:
Cast "inner" (after the colon in the enhancer for) to Iterable<Something>.

Workaround 2:
Manually desugar the enhanced for.


Comments
Please add due date or plans for getting this regression addressed in 8u20
12-06-2014

Clarification of spec: see http://mail.openjdk.java.net/pipermail/compiler-dev/2014-June/008828.html
04-06-2014

If Client.java is modified to: package b; import a.*; class Client extends Outer { public void method(Inner inner) { for (Something st : inner) System.out.println(st); // or anything else } } then the code compiles just fine. So this is not an access problem but that Lower is using the scope of the original client class to look for members of the original OuterImpl class. The members of OuterImpl should be seek in it's scope not in Client's. So the problem IMO is not in the original fix but because we are using the environment of the outer class to process inner classes in Lower.
12-05-2014

This regression was introduced in changeset 1639. The type passed to lookMethod in Lower.visitIterableForeachLoop causes the problem.
24-04-2014