-
Bug
-
Resolution: Unresolved
-
P4
-
8, 9
-
generic
-
generic
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.
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.
- relates to
-
JDK-8233837 getConstructor() not working as expected
- Closed