JDK 25 |
---|
25 b16Fixed |
CSR :
|
|
Causes :
|
|
Duplicate :
|
|
Relates :
|
JDK-8352900 :
|
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.
|