| 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.
|