Since JEP 358, NullPointerException are providing more information about the cause of the exception by describing precisely which variable is null.
However, the current implementation of this extended description of the exception can produce erroneous message with null restricted fields.
For instance, when running the following program:
import jdk.internal.vm.annotation.NullRestricted;
import jdk.internal.vm.annotation.ImplicitlyConstructible;
import jdk.internal.vm.annotation.LooselyConsistentValue;
public class NPETest {
@ImplicitlyConstructible
@LooselyConsistentValue
static value class MyValue {
int i = 0;
}
@NullRestricted
MyValue val = new MyValue();
public static void main(String[] args) {
var test = new NPETest();
test.val = null;
}
}
The output is:
$ java --enable-preview NPETest
Exception in thread "main" java.lang.NullPointerException: Cannot assign field "val" because "<local1>" is null
at NPETest.main(NPETest.java:18)
When inspecting the NPETest class file, <local1> is the local variable containing the variable 'test' which is a newly created instance of NPETest and cannot be null at this point of the execution:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #11 // class NPETest
3: dup
4: invokespecial #16 // Method "<init>":()V
7: astore_1
8: aload_1
9: aconst_null
10: putfield #10 // Field val:LNPETest$MyValue;
13: return
LineNumberTable:
line 17: 0
line 18: 8
line 19: 13
The cause of the NPE is the attempt to write the null reference (from the aconst_null) to a null restricted field.
When JEP 358 was implemented, getfield and putfield had a single possible cause for throwing a NPE: a null receiver. So, the logic in ExceptionMessageBuilder::print_NPE_failed_action() was very simple.
But the addition of null restriction to fields introduced a second possible source of NPE. Trying to determine the real cause of the NPE will be an implementation challenge, because it requires a deep knowledge of implementation of the component (interpreter/C1/C2) which was executing the bytecode to inspect the different internal variable an check them for null.
A short term solution for the JEP 401 preview could be to have a slightly different NPE message for exceptions on null restricted fields, simply stating that either the receiver or the value is null. A better solution with a more accurate description of the cause of the NPE could be implemented later.
However, the current implementation of this extended description of the exception can produce erroneous message with null restricted fields.
For instance, when running the following program:
import jdk.internal.vm.annotation.NullRestricted;
import jdk.internal.vm.annotation.ImplicitlyConstructible;
import jdk.internal.vm.annotation.LooselyConsistentValue;
public class NPETest {
@ImplicitlyConstructible
@LooselyConsistentValue
static value class MyValue {
int i = 0;
}
@NullRestricted
MyValue val = new MyValue();
public static void main(String[] args) {
var test = new NPETest();
test.val = null;
}
}
The output is:
$ java --enable-preview NPETest
Exception in thread "main" java.lang.NullPointerException: Cannot assign field "val" because "<local1>" is null
at NPETest.main(NPETest.java:18)
When inspecting the NPETest class file, <local1> is the local variable containing the variable 'test' which is a newly created instance of NPETest and cannot be null at this point of the execution:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #11 // class NPETest
3: dup
4: invokespecial #16 // Method "<init>":()V
7: astore_1
8: aload_1
9: aconst_null
10: putfield #10 // Field val:LNPETest$MyValue;
13: return
LineNumberTable:
line 17: 0
line 18: 8
line 19: 13
The cause of the NPE is the attempt to write the null reference (from the aconst_null) to a null restricted field.
When JEP 358 was implemented, getfield and putfield had a single possible cause for throwing a NPE: a null receiver. So, the logic in ExceptionMessageBuilder::print_NPE_failed_action() was very simple.
But the addition of null restriction to fields introduced a second possible source of NPE. Trying to determine the real cause of the NPE will be an implementation challenge, because it requires a deep knowledge of implementation of the component (interpreter/C1/C2) which was executing the bytecode to inspect the different internal variable an check them for null.
A short term solution for the JEP 401 preview could be to have a slightly different NPE message for exceptions on null restricted fields, simply stating that either the receiver or the value is null. A better solution with a more accurate description of the cause of the NPE could be implemented later.
- duplicates
-
JDK-8349103 [lworld] Misleading exception method for assigning null to a NullRestricted field
-
- Closed
-