Summary
Currently, an inner class instance with null
enclosing instances can be created by reflection, method handles, or direct bytecode invocation. The java compiler's translation of inner class constructors will add a null check to the incoming immediately enclosing instance argument (unless this argument is delegated to another this() constructor call) to block such creations.
Problem
JLS provides that various use sites of inner class constructors should include null checks if the incoming immediately enclosing instance may be null
, including for qualified instance creation expressions (JLS 15.9.4) and superconstructor invocations (JLS 8.8.7.1 "if the superclass constructor invocation is qualified"). Then, JLS assumes the enclosing instances are non-null in the usages in inner classes.
However, JLS does not mandate any check in the declaration site of the inner class constructors. As a result, core reflection, method handles, or direct bytecode invocation may pass null
for inner class constructors, and the usages of the enclosing instances later may see null
and fail with an NPE.
Solution
javac will start emitting null checks in inner class constructors that calls a superclass constructor. Such constructors store to the synthetic field that captures the immediately enclosing instance. Other constructors all delegate to constructors that call superclass constructors.
This is purely an implementation artifact with no JLS changes. In addition, these null checks will be emitted, even if the enclosing instance is unused and not stored into a field. These null checks will be emitted regardless of source or target releases.
Note that the original compiler-generated null checks for the JLS 15.9.4 and 8.8.7.1 provisions are kept as-is. They currently causes an NPE before other exceptions can arise, such as any run-time LinkageError
or any error thrown by the inner class constructors (such as one that calls a super constructor with a static method that throws an unchecked exception), which the checks added by this solution do not cover.
Specification
No change.
It seems the word "instance" in the JLS means the presence of an object, as in "class instance", as opposed to null references. Therefore, null-checking a parameter that must pass an instance makes sense.
- csr of
-
JDK-8164714 Constructor.newInstance creates instance of inner class with null outer class
-
- In Progress
-