JDK-8356696 : javac accepts illegal modifier on local class in violation of JLS 14.3
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 16,25
  • Priority: P3
  • Status: Resolved
  • Resolution: Not an Issue
  • OS: generic
  • CPU: generic
  • Submitted: 2025-05-10
  • Updated: 2025-10-25
  • Resolved: 2025-10-25
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 26
26Resolved
Related Reports
Causes :  
Description
ADDITIONAL SYSTEM INFORMATION :
macOS version:

```
Software:

    System Software Overview:

      System Version: macOS 13.2 (22D49)
      Kernel Version: Darwin 22.3.0
      Boot Volume: Macintosh HD
      Boot Mode: Normal
      Computer Name: MacBook Pro
      User Name: MacBook
      Secure Virtual Memory: Enabled
      System Integrity Protection: Enabled
      Time since boot: 1 day, 2 hours, 19 minutes

Hardware:

    Hardware Overview:

      Model Name: MacBook Pro
      Model Identifier: MacBookPro18,1
      Model Number: MK193CH/A
      Chip: Apple M1 Pro
      Total Number of Cores: 10 (8 performance and 2 efficiency)
      Memory: 16 GB
      System Firmware Version: 8419.80.7
      OS Loader Version: 8419.80.7
      Activation Lock Status: Disabled
```

OpenJDK version:

```
openjdk version "11.0.27" 2025-04-15
OpenJDK Runtime Environment Temurin-11.0.27+6 (build 11.0.27+6)
OpenJDK 64-Bit Server VM Temurin-11.0.27+6 (build 11.0.27+6, mixed mode)

openjdk version "17.0.15" 2025-04-15
OpenJDK Runtime Environment Temurin-17.0.15+6 (build 17.0.15+6)
OpenJDK 64-Bit Server VM Temurin-17.0.15+6 (build 17.0.15+6, mixed mode, sharing)

openjdk version "21.0.7" 2025-04-15 LTS
OpenJDK Runtime Environment Temurin-21.0.7+6 (build 21.0.7+6-LTS)
OpenJDK 64-Bit Server VM Temurin-21.0.7+6 (build 21.0.7+6-LTS, mixed mode, sharing)
```

A DESCRIPTION OF THE PROBLEM :
The following test program declares a local class within a code block. When compiled with `javac` of JDK 17 or JDK 21, it compiles without any error. However, compiling the same code using `javac` of JDK 11 or the Eclipse Compiler for Java (ECJ) results in a compilation error.

```
public class Test {
    public static void main(String[] args) {
        var outer = new java.lang.Object() {
            private class Inner {
                public void method() {
                    System.out.println("Inner local class method");
                }
            }
        };
    }
}
```

### Observed Behavior:

Using `javac` of JDK17 or JDK21, the program compiles successfully without any error.

```
>>> pathToJDK17/javac Test.java
>>> pathToJDK21/javac Test.java
```

However, using `javac` of JDK 11:

```
>>> pathToJDK11/javac Test.java
Test.java:4: error: modifier private not allowed here
            private class Inner {
                    ^
1 error
```

and, compiling the same code with **ECJ** produces the following error:

```java
>>> java -cp . -jar ecj-4.36.jar --release 21 -d . Test.java
----------
1. ERROR in /Test.java (at line 4)
        private class Inner {
                      ^^^^^
Illegal modifier for the local class Inner; only abstract or final is permitted
----------
1 problem (1 error)
```

According to the [Java Language Specification, §14.3](https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.3):

> “It is a compile-time error if a local class or interface declaration has any of the access modifiers public, protected, or private (§6.6).”
> 

This means local classes must not use access modifiers like `private`.

ECJ and JDK 11 correctly reject the code, adhering to the specification.

However, JDK 17 and JDK 21’s `javac` compilers silently accept it, which contradicts the language specification and may indicate a potential bug.

REGRESSION : Last worked in version 11.0.27

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile `Test.java` using `javac` from JDK 17 or JDK 21 — observe that it compiles successfully.
2. Compile `Test.java` using `javac` from JDK 11 — observe the compilation error.
3. Compile `Test.java` using ECJ (e.g., version 4.36) — observe the error.
4. Compare the outputs for consistency with the Java Language Specification.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program should report a compile-time error.
ACTUAL -
The program compiles successfully without any error.

---------- BEGIN SOURCE ----------
public class Test {
    public static void main(String[] args) {
        var outer = new java.lang.Object() {
            private class Inner {
                public void method() {
                    System.out.println("Inner local class method");
                }
            }
        };
    }
}
---------- END SOURCE ----------


Comments
The body of an anonymous class functions in most ways like a normal class body—see JLS 15.9.5. "The ClassBody of the class instance creation expression or enum constant declares fields (§8.3), methods (§8.4), member classes (§8.5), member interfaces (§9.1.1.3), instance initializers (§8.6), and static initializers (§8.7) of the anonymous class." As Archie says, the class 'Local' is a member class, subject to the same rules as any other member class.
25-10-2025

Just to clarify. In this code: var outer = new java.lang.Object() { private class Local { public void method() { System.out.println("Inner local class method"); } } The class "Local" is not a local class, it's a member class. The class of which it is a member is the anonymous class that extends Object.
12-05-2025

Additional information received from the submitter: According to the response, starting with JDK 16, static members can be declared in inner classes (we believe it is more accurate to describe these as *local classes* in this context). We conducted a verification by modifying the test program as follows: ```java public class Test { public static void main(String[] args) { var outer = new java.lang.Object() { static class Local { public void method() { System.out.println("Inner class method"); } } }; } } ``` When compiling this program using JDK 11, the following error is thrown: ``` Test.java:4: error: modifier static not allowed here static class Local { ^ 1 error ``` However, using JDK 17 and JDK 21, the program compiles successfully. This appears to align with the explanation: *"Since JDK 16, static members can be declared in inner classes."* That said, this seems like a different issue from what we originally reported. In our initial test case, the keyword used was `private`, not `static`: ```java public class Test { public static void main(String[] args) { var outer = new java.lang.Object() { private class Local { public void method() { System.out.println("Inner local class method"); } } }; } } ``` And we have checked the latest [Java Language Specification, §14.3](https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.3), which clearly states: > “It is a compile-time error if a local class or interface declaration has any of the access modifiers public, protected, or private (§6.6).” > Furthermore, as confirmed in the attachments of [JDK-8254321](https://bugs.openjdk.org/browse/JDK-8254321), there has been no update to this part of the specification. Could it be that there is an intention to permit these modifiers, but the specification has not yet been updated? If so, this risks introducing discrepancies among Java compilers that adhere strictly to the JLS. Therefore, does this indicate a compiler inconsistency, or simply a case of the specification not being updated in time? We’d greatly appreciate it if you could provide further clarification on the rationale behind this decision.
12-05-2025

Impact -> H (Regression) Likelihood -> L (Not an issue) Workaround -> M (Somewhere in-between the extremes) Priority -> P3
11-05-2025

The issue is caused by JDK-8254321. Since JDK 16 static members can be declared in inner classes. Closed as not an issue.
11-05-2025