7

I have a very strange problem with NullPointerException. Code example is as follows:

...
... public String[] getParams(...) {
...   ...
...   ... 
143   return new String[] {
144     getUserFullName(),
145     StringUtil.formatDate(sent),
 .      tiltu,
 .      StringUtil.initCap(user.getName()),
 .      vuosi.toString(),
 .      asiatyyppi[0] + " " + lisatiedot[0],
 .      asiatyyppi[1] + " " + lisatiedot[1],
 .      alaviitteet[0],
152     alaviitteet[1]};
153  }

Now, I have got an issue from production having a stack trace:

java.lang.NullPointerException
    at package.EmailService.getParams(EmailService.java:143)
...

I am unable to produce that kind of stack trace myself. It maybe some environment issue that for some reason line numbers don't match. If I have null references on any variable stack trace points to that specific line but never to line 143.

But what I want to ask is: is it possible to produce NullPointerException at line 143 specifically?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
M.L.
  • 4,686
  • 1
  • 19
  • 15
  • Check if any of the following are null: `tiltu`, `vuosi`, `asiatyyppi`, `lisatiedot`, `alaviitteet` – Steve Chaloner May 11 '15 at 05:42
  • try printing individual elements like ; user, vuosi, asiatyyppi .... – Saurabh Jhunjhunwala May 11 '15 at 05:42
  • 1
    Many of those could have a `null` value. Use a debugger. If you can't reproduce, then do `null` checks for everything before the return line and log those values. If you ever come across the exception again, then you'll know more – But I'm Not A Wrapper Class May 11 '15 at 05:44
  • 1
    The OP is not asking to solve his NullPointer problem, he's asking whether it's possible to have an exception at line 143 (the line that says `new String[]`) because one would assume that if any of the variables were `null`, the line number would be 144 to 152, not 143. – Erwin Bolwidt May 11 '15 at 05:47
  • @Jens it's clearly not a duplicate of that question; the OP has a very specific and different question. – Erwin Bolwidt May 11 '15 at 05:48
  • I don't see this as a dupe either. This is an NPE on *instantiation*. While I'm also sure it's been asked somewhere, that particular answer doesn't cover this scenario. – Makoto May 11 '15 at 05:49
  • IMO line 143 could never throw a NPE unless since you are saying that code might be out of sync, its possible that subsequent one/few lines were on line 143 i the released code – Nitin Dandriyal May 11 '15 at 06:09

2 Answers2

5

Consider your original code which defines a new String array:

return new String[] {
    getUserFullName(),
    StringUtil.formatDate(sent),
    tiltu,
    StringUtil.initCap(user.getName()),
    vuosi.toString(),
    asiatyyppi[0] + " " + lisatiedot[0],
    asiatyyppi[1] + " " + lisatiedot[1],
    alaviitteet[0],
    alaviitteet[1]};
}

If any of the elements of the inline array should trigger a NullPointerException the JVM will interpret the Exception as having occurred on the line where the definition began. In other words, the JVM will view the above code as being the same as:

return new String[] { getUserFullName(), StringUtil.formatDate(sent), tiltu, StringUtil.initCap user.getName()), vuosi.toString(), asiatyyppi[0] + " " + lisatiedot[0], asiatyyppi[1] + " " + lisatiedot[1], alaviitteet[0], alaviitteet[1]}; }

where everything is on one line.

If you really want to handle NullPointerExceptions here, you should define the variables outside the instantiaition.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
  • 2
    that's not exactly correct, actually it throws the nullpointer exception in the line that absoultely in throwing line. – Sercan Ozdemir May 11 '15 at 05:56
  • 1
    That sounds like an interesting proposition, but do you have anything to back that up? I do have a simple counterexample - just try `Object x = null; String[] y = new String[] { x.toString() };` and spread that out over multiple lines. You'll see that the NullPointerException is reported on the line where `x.toString()` is called. So I think **your reasoning is incorrect**. – Erwin Bolwidt May 11 '15 at 05:56
  • What compiler are you using? – Erwin Bolwidt May 11 '15 at 06:00
  • @TimBiegeleisen which Java version (jvm ver. ) are you using ? – Sercan Ozdemir May 11 '15 at 06:00
  • The test was run in IntelliJ using JDK 7. Are things different in JDK 8 ^ ^ ? – Tim Biegeleisen May 11 '15 at 06:01
  • I've tested with Oracle Javac 1.8 and also Eclipse Luna 4.4.2 with source and class files set to 1.8. But that shouldn't make a difference. Line numbers are recorded in the class file and that hasn't changed for a long time, NullPointerExceptions have always been reported at the line that caused them. – Erwin Bolwidt May 11 '15 at 06:06
  • JDK7 and Tomcat is used on production. I do not know the specific version of that though. – M.L. May 11 '15 at 06:12
  • 1
    I retract the last part of my previous statement - this seems to be exactly a bug in the javac compiler that has been fixed in 1.8 – Erwin Bolwidt May 11 '15 at 06:20
5

The line number in the stack trace comes from the LineNumberTable attribute in the class file. (See JVM specification)

It would be no problem to output the right line number for a subexpression - all the compiler has to do is to say that from byte-code index x to y, there is a correspondence with source code line z.

But up to and including Java 1.7 there was a bug in the compiler, that was fixed in 1.8:

https://bugs.openjdk.java.net/browse/JDK-7024096

A DESCRIPTION OF THE PROBLEM : linenumbertable in compiled code only has line numbers for starts of statements. When a statement is using method chaining or other "fluent Interface" style API's a single statement can span tens of lines and contain hundreds on method invocations.

Currently an exception throw from within any of these methods will have the linenumber of the first line of the enclosing statement which makes it very hard to debug which method call is having a problem.

linnumbertable should have correct line numbers for every method invocation.

--

BT2:EVALUATION

It seems simple enough to fix this, but its kinda risky at the end of the jdk7 development cycle, targetting to jdk8.

So in 1.7, you would get the wrong reported line number for these kind of subexpressions (if they occurred within the same method though - if you invoked another method in a subexpression, and that other method caused a NullPointerException, you would see it reported there - this is probably why the bug isn't always a big problem)

One way you could work around this is by taking the Java 8 compiler to compile your source code, and use the flags javac -source 1.7 -target 1.7. But it would be better and safer to upgrade your prod environment to 1.8.

Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79