JDK-8164714 : Constructor.newInstance creates instance of inner class with null outer class
  • Type: Bug
  • Component: tools
  • Sub-Component: javac
  • Affected Version: 8,9
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2016-08-17
  • Updated: 2025-07-31
  • Resolved: 2025-03-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 25
25 b16Fixed
Related Reports
CSR :  
Causes :  
Duplicate :  
Relates :  
Sub Tasks
JDK-8352900 :  
Description
FULL PRODUCT VERSION :
openjdk version "1.8.0_91"
OpenJDK Runtime Environment (build 1.8.0_91-b14)
OpenJDK 64-Bit Server VM (build 25.91-b14, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Linux godwit.cs.washington.edu 4.4.6-200.fc22.x86_64 #1 SMP Wed Mar 16 22:13:40 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
Creating an instance of an inner class always requires a non-null outer class.

However, it is possible to call Constructor.newInstance() to create an instance of an inner class with a null outer class, at least when the outer class declares no fields.
Please see the below code, which reproduces the error.

Proposed resolution:  newInstance for an inner class should throw a NullPointerException whenever the first argument is null.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
javac NullOuterTest.java
java -ea -cp . NullOuterTest

where NullOuterTest.java is in the "Source code" part of this issue report.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expected:
Both calls to invokeReflectively should issue a NullPointerException
ACTUAL -
Actual:
The first call to invokeReflectively completes normally, creating an illegal object.
The second call to invokeReflectively issues a NullPointerException, as desired.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.lang.reflect.*;

class ClassWithInnerClass {
  public class A {
    public String toString() {
      return String.format("ClassWithInnerClass.A(outer=%s)",
                           ClassWithInnerClass.this);
    }
  }
}

class ClassWithInnerClassAndField {
  int i;
  public class A {
    public String toString() {
      return String.format("ClassWithInnerClass.A(outer=%s, i=%s)",
                           ClassWithInnerClassAndField.this, i);
    }
  }
}

public class NullOuterTest {
  public static void main(String[] args) {


    System.out.println("Using reflection:");
    // expected: this first invocation should fail with a NullPointerException
    invokeReflectively(ClassWithInnerClass.class, null);
    // this second invocation correctly fails with a NullPointerException
    invokeReflectively(ClassWithInnerClassAndField.class, null);

    System.out.println("Executing directly:");
    try {
      ClassWithInnerClass outerObj = null;
      ClassWithInnerClass.A a2 = outerObj.new A();
      System.out.println("Created object with null outer: " + a2);
    } catch (NullPointerException e) {
      System.out.println("NPE when creating object with null outer");
    }

  }

  private static void invokeReflectively(Class<?> outerClass, Object outerObj) {
    Constructor<?> c = getInnerConstructor(outerClass);
    System.out.println("Constructor: " + c);
    try {
      Object obj = c.newInstance(outerObj);
      System.out.println("Created object with null outer: " + obj);
    } catch (Throwable e) {
      System.out.printf("failure calling constructor; type=%s; message=%s%n",
                        e.getClass(), e.getMessage());
    }
  }

  private static Constructor<?> getInnerConstructor(Class<?> outerClass) {
    Constructor<?> constructor = null;
    Class<?>[] innerClasses = outerClass.getDeclaredClasses();
    assert innerClasses.length == 1: "should only be one inner class";
    Class<?> innerClass = innerClasses[0];
    try {
      constructor = innerClass.getConstructor(outerClass);
    } catch (NoSuchMethodException e) {
      assert false : "no constructor; message=" + e.getMessage();
    }
    return constructor;
  }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Clients can check whether newInstance is called on an inner class constructor and whether the first argument is null.  If both are true, the client should not perform the call.


Comments
Changeset: 60544a15 Branch: master Author: Chen Liang <liach@openjdk.org> Date: 2025-03-25 19:01:02 +0000 URL: https://git.openjdk.org/jdk/commit/60544a15d6bd9fc17f362cdfb95f06e733934b05
25-03-2025

A pull request was submitted for review. Branch: master URL: https://git.openjdk.org/jdk/pull/23875 Date: 2025-03-03 21:49:55 +0000
05-03-2025

I think I evaluated and closed this bug incorrectly before. This should be "won't fix" as any arbitrary null checks added by core reflection or method handles can be bypassed by class generation.
03-03-2025

Before the bug is considered fully closed, it would be preferable to find out which changes elicited the change in behavior.
03-03-2025

I think beginning in some version javac started to generate null checks in inner class constructors to ensure the enclosing instance is not null. For example, it does not happen on java 23.
26-02-2025

Checked this issue for 8,8u102,9ea on Windows 7 and could reproduce the issue as reported by the bug submitter. Steps to reproduce: ************************* - Run the attached test application(NullOuterTest.java) with JDK. Result: ********* OS : Windows 7 64 bit JDK: 8 b132 : Fail 8u102 b14 : Fail 9ea+126 : Fail O/P: ****** Using reflection: Constructor: public com.oracle.java.corelibs.ClassWithInnerClass$A(com.oracle.java.corelibs.ClassWithInnerClass) Created object with null outer: ClassWithInnerClass.A(outer=null) Constructor: public com.oracle.java.corelibs.ClassWithInnerClassAndField$A(com.oracle.java.corelibs.ClassWithInnerClassAndField) failure calling constructor; type=class java.lang.NullPointerException; message=null Executing directly: NPE when creating object with null outer ===========================================================================================
24-08-2016

Assigning to Abhijit for analysis.
18-08-2016