14

I have an error servlet configured in my web.xml:

<error-page>
    <exception-type>java.lang.Exception</exception-type>
    <location>/ExceptionHandler</location>
</error-page>

right?

In my (generically) servlet:

doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        ...
        ...
    } catch (Exception e) {
        throw new ServletException("some mesage", e);
    }
}

so, "e" will be the root cause in this case.

In my ExceptionHandler class, I have:

doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
    throwable.getCause() //NULL
}

this is the problem. throwable.getCause() is null.

SJuan76
  • 24,532
  • 6
  • 47
  • 87
bluefoot
  • 10,220
  • 11
  • 43
  • 56
  • 1
    are you sure that this is the same exception and you are not mixing things up? BTW, your "generic servlet" code has a typo in exception handling code and does not compile. – Neeme Praks Nov 17 '10 at 18:35
  • Maybe instead of new ServletException("some message", e) you have new ServletException("some message" + e)? Would make sense to inspect the supplied Throwable object carefully, to see maybe you have a bug somewhere in your code. ;-) – Neeme Praks Nov 17 '10 at 18:41
  • I wrote the "generic servlet" now. please ignore syntax errors. – bluefoot Nov 17 '10 at 18:47
  • I can't use new ServletException("some message" + e) unless e.toString() gives me all the stack trace. That's what I want. The original line of the error. – bluefoot Nov 17 '10 at 18:48
  • never mind my comments, I just added an answer :-) – Neeme Praks Nov 17 '10 at 18:49

2 Answers2

26

If the exception caught by the servletcontainer is a ServletException and the <error-page> is declared to catch an exception other than ServletException, then its cause will actually be unwrapped and stored as "javax.servlet.error.exception". So you basically already have it as throwable variable and you don't need to call getCause() on it.

See also 5th paragraph of chapter 9.9.2 of Servlet 2.5 specification:

If no error-page declaration containing an exception-type fits using the class-hierarchy match, and the exception thrown is a ServletException or subclass thereof, the container extracts the wrapped exception, as defined by the ServletException.getRootCause method. A second pass is made over the error page declarations, again attempting the match against the error page declarations, but using the wrapped exception instead.

By the way, it's better to use the RequestDispatcher#ERROR_EXCEPTION constant instead of hardcoding it.

Throwable throwable = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I know. thanks. it's an old system that I'm kinda hard fixing. The problem is that the top of the stack trace is the line " throw new..." in the servlet, and not the real cause of the exception. The real cause is inside the block try {}, right? right. :) – bluefoot Nov 17 '10 at 18:59
  • 1
    Servlets are by contract required to wrap any catched exceptions in a `ServletException` so that you can utilize servletcontainer's facilities to handle it further. The original exception will be unwrapped and treated further as is. – BalusC Nov 17 '10 at 19:01
  • 1
    I guess my servlet implementation (2.4) with java 5 does not have this constant. – bluefoot Nov 17 '10 at 19:03
  • Maybe you've imported the wrong interface? It should be the `javax.servlet.RequestDispatcher` one (click the link in answer to see javadoc). You may accidently have autocompleted the wrong one in your IDE. Jersey (JAX-RS) for example also has such an interface. – BalusC Nov 17 '10 at 19:04
  • If you are using Servlet API 2.4 then I would recommend you to update your code as per my suggestion (see my answer) and see if it makes the problem go away. – Neeme Praks Nov 17 '10 at 19:13
  • @Neeme: It's already solved :) The OP only cannot seem to locate the constant. – BalusC Nov 17 '10 at 19:14
  • I'm not convinced that it is solved, he still seems to be struggling to see "the real cause of the exception". :-P – Neeme Praks Nov 17 '10 at 19:20
  • Maybe your `/WEB-INF/lib` folder is cluttered with outdated servletcontainer-specific libraries like `servlet-api.jar`. Get rid of them. – BalusC Nov 17 '10 at 19:24
  • @user468508 What servlet container (+version) are you actually running this on? And Java version? – Neeme Praks Nov 17 '10 at 19:28
  • it seems that other people are also confused about this automatic un-wrapping (http://alicia.orconhosting.net.nz/computer/scwcd/SCWCDNotesSec4.html), so this might be container-specific. Better write in a check for ServletException, just in case. – Neeme Praks Nov 17 '10 at 19:51
  • @Neeme: that would have been a bug in the servletcontainer since that's just clearly specified in error handling sections of the Servlet API specification (in case of version 2.5, see chapter 9.9.2, 5th paragraph). I have however never seen such a container yet. – BalusC Nov 17 '10 at 19:53
  • @BalusC: right. this is an old software that indeed has servlet-api.jar in the /WEB-INF/lib, although the servlet container is: apache tomcat 6.0.26.0 with java 6 – bluefoot Nov 17 '10 at 20:55
  • i'm sorry, but RequestDispatcher.ERROR_EXCEPTION will just replace "javax.servlet.error.exception"? – bluefoot Nov 17 '10 at 20:58
  • Tomcat 6 is a Servlet 2.5 container (`web.xml` should by the way preferably be modified to match Servlet 2.5 spec). And yes, `RequestDispatcher.ERROR_EXCEPTION` should be preferred over hardcoding its value. It's a constant provided by the API. You can of course also keep hardcoding, it will work, but that's just a poor practice. – BalusC Nov 17 '10 at 21:03
  • @BalusC: I couldn't agree more that RequestDispatcher.ERROR_EXCEPTION should be preferred over hardcoding its value. I just point that this might not solve the problem. But I guess removing the libs maybe do so. – bluefoot Nov 17 '10 at 21:09
  • I have never said that it should solve the problem as mentioned in your question. It's just a "by the way". The answer to your problem is that you don't need to call `getCause()`. You already have it as `throwable`. Reread the textual content of my answer. Don't focus on code snippets only. – BalusC Nov 17 '10 at 21:11
  • I'm not looking at code snippets, nor even textual context. I'm looking far above :) i'll perform the changes and report if it works. – bluefoot Nov 17 '10 at 21:19
  • @BalusC: ok I removed servlet-api.jar from project's WEB-INF/lib and still the same: java.lang.Exception cannot be cast to javax.servlet.ServletException. I also modified web.xml to "catch" only ServletExceptions but still the same. But I guess the problem may be another issue here. Guess my core question has already been answered. thanks. – bluefoot Nov 23 '10 at 14:38
  • Once again, you do not need to cast it. You do not need to call getCause(). You already have the original exception. It's the `e` which you caught in the catch block of the servlet code. Just work on the `Throwable` which you obtained as request attribute. That's it. – BalusC Nov 23 '10 at 14:40
  • As far as I see, at least some servlet containers would always unpack ServletExceptions (and descendants), even if exception-type is set to ServletExceptions. – Mikhail Feb 07 '19 at 21:59
-1

EDITED.

Ok, this might be wrong, I do not have personal experience with error handling servlets: Instead of getCause(), add an instanceof check for ServletException, if it passes, cast your Throwable to ServletException and use getRootCause(). (BalusC seems to have a better solution, for newer Servlet API versions)

See Exceptions Without Root Cause for in-depth discussion.

Newer Servlet API versions do not have this issue, but if you are using some old version (2.4 or older) you should also update your ServletException throwing code:

doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        ...
        ...
    } catch (Exception e) {
        ServletException se = new ServletException(e.getMessage(), e);
        se.initCause(e);
        throw se;
    }
}
Neeme Praks
  • 8,956
  • 5
  • 47
  • 47
  • java.lang.Exception cannot be cast to javax.servlet.ServletException. maybe if I change web.xml in exception-type ? – bluefoot Nov 17 '10 at 18:56
  • @user: It's indeed not a `ServletException` at all. Did you see my answer? – BalusC Nov 17 '10 at 18:58
  • Yep, better follow BalusC suggestion, I also updated my answer. – Neeme Praks Nov 17 '10 at 18:59
  • @Neeme: your updated code makes also no sense at all. It already sets the cause internally. Also, the `getRootCause()` just delegates to the `getCause()`. Did you see my answer? – BalusC Nov 17 '10 at 18:59
  • Depends on the version of Servlet API, did you see the page I linked to? It is outdated (2005) but you cannot make too many assumptions about the Servlet API version, so I guess my answer still has some value for legacy Servlet API users. – Neeme Praks Nov 17 '10 at 19:09
  • Could be, but OP isn't using Servlet 2.2 or older. – BalusC Nov 17 '10 at 19:12
  • Also 2.4 has this issue: http://www.jdocs.com/servlet/2.4/javax/servlet/ServletException.html – Neeme Praks Nov 17 '10 at 19:18
  • How so? This issue is caused by running webserver on top of Java SE 1.3 or older. Plus, the linked page treats a completely different problem. The request attribute contains the root cause of the exception. Period. The servletcontainer is smart enough to grab it by `getRootCause()` before setting as request attribute. – BalusC Nov 17 '10 at 19:21
  • As long as we do not know the exact servlet container (+ version) and java version, nothing is certain. This seems to be somewhat gray area and can vary between containers. – Neeme Praks Nov 17 '10 at 19:53