views:

558

answers:

8

I've had instances of our Java code catch a NullPointerException, but when I try to log the StackTrace (which basically ends up calling Throwable.printStackTrace() ), all I get is:

java.lang.NullPointerException

Has anyone else come across this? I tried googling for "java null pointer empty stack trace" but didn't come across anything like this.

+8  A: 

exception.toString does not give you the StackTrace, it only returns

a short description of this throwable. The result is the concatenation of:

* the name of the class of this object
* ": " (a colon and a space)
* the result of invoking this object's getLocalizedMessage() method

Use exception.printStackTrace instead to output the StackTrace.

Peter Lang
Sorry, I misspoke in my original post. I'm logging these through Log4J, which does use printStackTrace().
Edward Shtern
Have you tried using `getStackTrace()` to make sure the problem is not with your logger?
Peter Lang
If you are using log4j, be sure to send the exception as part of the argument to the log method. I will post an answer with that.
Ravi Wallau
Or not, someone already did that :-)
Ravi Wallau
@raviaw valid point! @Edward Shtern: can you confirm that you definitely are using the 2-arg form of the log4j method? I know you mentioned in an answer further down that it is the company policy to do so, but are you ABSOLUTELY sure that in this case you are following the policy?
KarstenF
@KarstenF - yup
Edward Shtern
It might be a long shot, but is it possible that the exception originates in some 3rd party code? Maybe it is a (poorly written) exception wrapper, whose toString() simply returns the class name of the wrapped exception, and which fails to provide the underlying stack trace. Try put something like logger.info("Exception class = " + exc.class.getCanonicalName()) into your catch block and see what you get.
KarstenF
A: 

toString() only returns the exception name and the optional message. I would suggest calling

exception.printStackTrace()

to dump the message, or if you need the gory details:

 StackTraceElement[] trace = exception.getStackTrace()
Sheldon Young
See above - I misspoke - I am using printStackTrace().
Edward Shtern
A: 

This will output the Exception, use only to debug you should handle you exceptions better.

import java.io.PrintWriter;
import java.io.StringWriter;
    public static String getStackTrace(Throwable t)
    {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw, true);
        t.printStackTrace(pw);
        pw.flush();
        sw.flush();
        return sw.toString();
    }
JeremySpouken
+11  A: 

As you mentioned in a comment, you're using log4j. I discovered (inadvertently) a place where I had written

LOG.error(exc);

instead of the typical

LOG.error("Some informative message", e);

through laziness or perhaps just not thinking about it. The unfortunate part of this is that it doesn't behave as you expect. The logger API actually takes Object as the first argument, not a string - and then it calls toString() on the argument. So instead of getting the nice pretty stack trace, it just prints out the toString - which in the case of NPE is pretty useless.

Perhaps this is what you're experiencing?

Steven Schlansker
+1: This would explain the described behavior, and you are not the only one who discovered this :)
Peter Lang
We actually have a standard policy of never using the first form above (LOG.error(exc);) - we always use the 2 parameter signature so that we add some descriptive statement to the logs instead of just a raw stacktrace.
Edward Shtern
Sure, but policy doesn't mean it's always executed correctly! Figured it was worth mentioning, at least.
Steven Schlansker
True, but in this case it was ;-)
Edward Shtern
A: 

Alternate suggestion - if you're using Eclipse, you could set a breakpoint on NullPointerException itself (in the Debug perspective, go to the "Breakpoints" tab and click on the little icon that has a ! in it)

Check both the "caught" and "uncaught" options - now when you trigger the NPE, you'll immediately breakpoint and you can then step through and see how exactly it is handled and why you're not getting a stack trace.

Steven Schlansker
A: 

(Your question is still unclear on whether your code is calling printStackTrace() or this is being done by a logging handler.)

Here are some possible explanations about what might be happening:

  • The logger / handler being used has been configured to only output the exception's message string, not a full stack trace.

  • Your application (or some third-party library) is logging the exception using LOG.error(ex); rather than the 2-argument form of (for example) the log4j Logger method.

  • The message is coming from somewhere different to where you think it is; e.g. it is actually coming some third-party library method, or some random stuff left over from earlier attempts to debug.

  • The exception that is being logged has overloaded some methods to obscure the stacktrace. If that is the case, the exception won't be a genuine NullPointerException, but will be some custom subtype of NPE or even some unconnected exception.

I think that the last possible explanation is pretty unlikely, but people do at least contemplate doing this kind of thing to "prevent" reverse engineering. Of course it only really succeeds in making life difficult for honest developers.

Stephen C
+4  A: 

We have seen this same behavior in the past. It turned out that, for some crazy reason, if a NullPointerException occurred at the same place in the code multiple times, after a while using Log.error(String, Throwable) would stop including full stack traces.

Try looking further back in your log. You may find the culprit.

EDIT: this bug sounds relevant, but it was fixed so long ago it's probably not the cause.

Matt Solnit
This sounds interesting, I'll keep an eye out.
Edward Shtern
+2  A: 

You are probably using the Sun JVM, which performs a lot of optimization. To get the stack traces back, you need to pass the option -XX:-OmitStackTraceInFastThrow to the JVM.

Roland Illig
Thanks for the tip. Any idea if there are any hidden gotchas to passing this option (it seems pretty innocuous as long as my application doesn't throw a ton of exceptions)?
Edward Shtern
There are no hidden gotchas that I know of. When you look at the Hotspot source code, you can see that this option is only used in one place (graphKit.cpp). And that looks fine to me.
Roland Illig