When I get an NPE, I'll get a stack trace with line number. That's helpful, but if the line is very dense and/or contains nested expression, it's still impossible to figure out which reference was null.
Surely, this information must've been available somewhere. Is there a way to figure this out? (If not java expression, then at least the bytecode instruction that caused NPE would be helpful as well)
Edit #1: I've seen a few comments suggesting breaking up the line, etc, which, no offence, is really non-constructive and irrelevant. If I could do that, I would have ! Let just say this modifying the source is out of the question.
Edit #2: apangin has posted an excellent answer below, which I accepted. But it's SOOO COOL that I had to include the output here for anyone who doesn't want to try it out themselves! ;)
So suppose I have this driver program TestNPE.java
1 public class TestNPE {
2 public static void main(String[] args) {
3 int n = 0;
4 String st = null;
5
6 System.out.println("about to throw NPE");
7 if (n >= 0 && st.isEmpty()){
8 System.out.println("empty");
9 }
10 else {
11 System.out.println("othereise");
12 }
13 }
14
15 }
The bytecode looks like this (showing only the main() method and omitting other irrelevant parts)
Code:
stack=2, locals=3, args_size=1
0: iconst_0
1: istore_1
2: aconst_null
3: astore_2
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #3 // String about to throw NPE
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: iload_1
13: iflt 34
16: aload_2
17: invokevirtual #5 // Method java/lang/String.isEmpty:()Z
20: ifeq 34
23: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
26: ldc #6 // String empty
28: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
31: goto 42
34: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
37: ldc #7 // String othereise
39: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
42: return
Now when you run the TestNPE driver with the agent, you'll get this
$ java -agentpath:libRichNPE.o TestNPE
about to throw NPE
Exception in thread "main" java.lang.NullPointerException: location=17
at TestNPE.main(TestNPE.java:7)
So that points to the invokevirtual #5 at offset 17! Just HOW COOL IS THAT?
Java
will print the relevant row number while still treating it as a line. – Junia