Getting Root Error Messages from Throwable
I'm working on my error handling on a web project that I'm doing and I ran into a case in which the error I was displaying to the user wasn't particularly helpful. I had been using this to get the error message in order to display to my use开发者_JS百科r:
catch (Throwable t) {
...
t.getMessage();
...
}
That generally works well and normally gives the user a better message than an ugly stack trace that they don't know what to do with. However, in one case, Hibernate was throwing an exception and the error message being displayed was:
could not insert [some.class.name.Here]
which is very unhelpful. The actual cause of the error was buried in the stack trace:
Only dates between January 1, 1753 and December 31, 9999 are accepted.
Given the first error message, I would have no idea what went wrong. Given the second, I would at least know to take a look at the date I entered. To solve this, I did this:
catch (Throwable t) {
...
ExceptionUtils.getExceptionMessageWithCauses(t);
...
}
...
public class ExceptionUtils
{
public static String getExceptionMessageWithCauses(Throwable t)
{
if ( t.getCause() == null ) {
return t.getMessage();
} else {
return t.getMessage()
+ "; caused by: "
+ getExceptionMessageWithCauses(t.getCause());
}
}
}
My first concern is that I may get into some sort of infinite loop should two Throwable classes reference one another. Or, similarly, the root cause is so deep that even displaying the more friendly error message from the Throwables results in something no better than a stack trace. So, two questions:
Is it "safe" to do something like this, or can people think of cases where this will blow up in my face?
Is there a better way to handle exceptions aside from checking for every possible error condition one by one?
Thanks!
Well, you'd normally validate user input on the web layer, thus you'd know what the wrong input was. If you get an SQLException from hibernate or the database driver, you normally can't automatically and beautifully get the real cause.
What we do is catch all exceptions that might mean anything to a user (they are normally checked exceptions), all other exceptions (normally RuntimeExceptions) are just handled with a "An internal error occured" message.
A general exception we have is a ValidationException
that is thrown by our validation framework and carries all data needed to generate a nice message (normally translatable).
Edit:
Sometimes it might be necessary to iterate through the causes in order to get an exception you display. For example, we have exceptions that are thrown by our persistence layer but they are passed through the EJB layer and thus get wrapped in EJBExceptions
. Thus we iterate through the causes until we find one of our exceptions and display a nice message or else display the 'internal error' one.
Note that normally a user shouldn't ever be confronted with the default error messages, since most don't know what that means ("Huh, what is a NullPointerException????")
精彩评论