3

When the exception is rethrown in the below code the original stack trace is not kept.

The Exception is thrown in line 148 & rethrown in line 150. After Rethrowing line 150 is the designated source of the exception.

What must I do to keep the original Stack trace?

Code:

    try {

        content = (InputStream) conn.getContent(); //line 148

    } catch (IOException e) {

        throw new RuntimeException(e); //line 150

    }

Original Stack Trace:

 (java.lang.StackTraceElement[]) [sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source), java.net.URLConnection.getContent(Unknown Source), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEle(AbstractClientService.java:148), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:162), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:158), com.mycompany.myapp.client.services.impl.InfoQueryClientServiceImpl.getFileOnTmpList(InfoQueryClientServiceImpl.java:84), com.mycompany.myapp.client.myappClient.getFileOnTmpList(myappClient.java:196), com.mycompany.myapp.client.model.Model.updateStudyInfos(Model.java:96), com.mycompany.myapp.client.model.Model.instantiateSingleton(Model.java:46), com.mycompany.myapp.applet.MainApplet.addMainPanel(MainApplet.java:106), com.mycompany.myapp.applet.MainApplet.createUIPanel(MainApplet.java:76), com.mycompany.myapp.applet.MainApplet.init(MainApplet.java:58), com.sun.deploy.uitoolkit.impl.awt.AWTAppletAdapter.init(Unknown Source), sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source), java.lang.Thread.run(Unknown Source)]

Stack Trace After rethrowing:

 (java.lang.StackTraceElement[]) [com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEle(AbstractClientService.java:150), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:162), com.mycompany.myapp.client.services.impl.AbstractClientService.getResponseEleWithCheck(AbstractClientService.java:158), com.mycompany.myapp.client.services.impl.InfoQueryClientServiceImpl.getFileOnTmpList(InfoQueryClientServiceImpl.java:84), com.mycompany.myapp.client.myappClient.getFileOnTmpList(myappClient.java:196), com.mycompany.myapp.client.model.Model.updateStudyInfos(Model.java:96), com.mycompany.myapp.client.model.Model.instantiateSingleton(Model.java:46), com.mycompany.myapp.applet.MainApplet.addMainPanel(MainApplet.java:106), com.mycompany.myapp.applet.MainApplet.createUIPanel(MainApplet.java:76), com.mycompany.myapp.applet.MainApplet.init(MainApplet.java:58), com.sun.deploy.uitoolkit.impl.awt.AWTAppletAdapter.init(Unknown Source), sun.plugin2.applet.Plugin2Manager$AppletExecutionRunnable.run(Unknown Source), java.lang.Thread.run(Unknown Source)] 
j0k
  • 22,600
  • 28
  • 79
  • 90
user1826324
  • 31
  • 2
  • 4

5 Answers5

3

Your code does not rethrow original exception, but throws new instance of RuntimeException which has its stack trace filled at point of creation.

You can ether call Throwable.getCause().getStackTrace() when you catch RuntimeException or set stack trace of RuntimeException to one from original exception before throwing RuntimeException.

Martin Andersson
  • 18,072
  • 9
  • 87
  • 115
Nemanja
  • 1,161
  • 11
  • 13
  • What would be best practice? – user1826324 Nov 15 '12 at 12:39
  • Since you're not doing anything in the catch block except for throwing the original exception, best practice would be to not catch it here at all. If you are wrapping it in a RuntimeException to circumvent defining a checked exception, just add it as a cause. Replacing the stacktrace will still result in loss of information since you then only have the stacktrace, not that it was an IOException. – Janoz Nov 15 '12 at 13:14
  • Perhaps the OP is wrapping the exception in an Runtime Exception to avoid 'polluting' method signatures with 'throws' clauses......? – monojohnny Oct 30 '14 at 13:14
  • Simply calling `getCause` may not be sufficient, as there could be multiple levels of wrapped Exceptions. See my answer: http://stackoverflow.com/a/27076790/194894 – Flow Nov 22 '14 at 11:21
2

The "problem" is that you are not rethrowing an exception. Rather you are throwing a new exception. If you do genuinely rethrow an exception like this:

try {
    content = (InputStream) conn.getContent();
} catch (IOException e) {
    throw e;
}

you will find that the stack trace is preserved.

And if you use Throwable.printStackTrace() on a modern JVM, it will show the chained exceptions and their (unique) stack frames. In other words, the information from the original exception is preserved.


There is a way to splice the stack trace from one exception into another.

try {
    content = (InputStream) conn.getContent();
} catch (IOException e) {
    RuntimeException re = new RuntimeException(e);
    re.setStackTrace(e.getStackTrace());
    throw re;
}

However, I personally don't think this is a good idea. While the line numbers for the RuntimeException are now the same as the original exception, you get the anomalous situation of a connection object appearing to throw a RuntimeException where the code says this cannot happen. I think it is better just to chain the exception in the normal way and leave it to the programmer to read the stack trace of the chained exception properly.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

If you only want the original stacktrace, don't catch it. On the other hand, I assume you wrapped it in a runtime exception for a reason. You can get the original exception from the runtime exception using getCause()

Janoz
  • 953
  • 4
  • 9
0

The stacktrace is kept.

You have to get the cause from the RuntimeException and get the stacktrace from there to get the origin.

This feature is call Exception-chaining.

Uwe Plonus
  • 9,803
  • 4
  • 41
  • 48
0

You have to follow the reference of the causing Throwables to get the original stacktrace. For example

public static StackTraceElement[] getCausingStacktrace(Throwable throwable) {
  if (throwable == null) {
    throw new NullPointerException();
  }
  while (throwable != null) {
    throwable = throwable.getCause();
  }
  return throwable.getStacktrace();
}
Flow
  • 23,572
  • 15
  • 99
  • 156