Exception Handling in a Java Web Application - java

I am developing a medium size Java Web Application with Struts as MVC framework and simple JDBC at Data Access Layer. I have been searching for exception handling best practices in such an application. I have found several articles, some of them being contradictory, only making me more confused rather than making things clear and simple. Some say it is better to reuse existing exceptions instead of defining application specific exceptions, others present a huge hierarchy of application specific exceptions for every minor trouble that may occur in the system. Some say it is better not to handle exceptions at Data Access Layer and delegate them to the Service Layer, others say Data Access Layer exceptions should be caught locally since delegating them to Service Layer would violate the abstraction between the two layers. And so on.
I would highly appreciate if you let me know of links/names to articles/books that present solid solutions which have worked for you in such a scenario. The solution should clear at least the following points with justifications:
Where the SQLExceptions be caught?
Where exceptions should be logged?
Should unchecked exceptions be logged?
Should unchecked exceptions be caught at presentation layer, and should they be shown to the user?
How checked exceptions be handled, which of them to be shown to the user and how?
How should a global exception handler page be used?
How should struts ActionErrors be used in this context?
Thanks

1: Where the SQLExceptions be caught?
In DAO classes in data access layer. You can if necessary wrap it with a custom DAO exception. This DAO exception in turn needs to be handled further as checked exception.
2: Where exceptions should be logged?
At the moment when you're about to throw them or to pass through the messaging framework.
3: Should unchecked exceptions be logged?
They should certainly be logged. They should namely not occur in real world, because those are sign of a fault in the code logic (i.e. developer fault) which needs to be bugfixed asap. They should be thrown all the way up to the container and let the container handle them with an <error-page> in web.xml. To log (and eventually mail) them, use a Filter which listens on the error page.
4: Should unchecked exceptions be caught at presentation layer, and should they be shown to the user?
They should not occur at all.
5: How checked exceptions be handled, which of them to be shown to the user and how?
If they are result of errorneous user input (e.g. not a number, bad email, constraint violation, etc), show them in the same form to the user. Otherwise (e.g. DB down, DAO exception and so on) either throw it all the way up to the error page, or display the error with a message to try again later.
6: How should a global exception handler page be used?
At least in an user-friendly manner. Thus, in the same layout, with some introductory "sorry" and if necessary with some error details and an email address so that the user can contact for the case that.
7: How should struts ActionErrors be used in this context?
Show them in same form to the user.

If you can't recover from an exception, then you should let it flow out of your code (often by making it unchecked, or wrapping it in an unchecked exception). If they remain checked, you have to cater for them at each level of your code, and consequently at every abstraction layer. SQLExceptions would normally fall into this category (you'll have to wrap them since they're checked).
For these exceptions, I normally log at the highest level, but present a page to the users simply detailing that something has gone wrong. Normally my users aren't interested in stack traces. But I usually offer them a page to let them describe what they were doing at the time, and the logged exception ties back to this submission via a unique id (recorded in the form and in the log file with the exception). That allows me to tie back users' actions to the resulting exception.
The above assumes that you can't recover from SQLExceptions, and if the database is down, then you can't do something meaningful. There are exceptions to this, of course. You may find that you're talking to multiple systems, and one being down doesn't mean you can't continue in some fashion (e.g. the Amazon home page reportedly relies on 100 services, and needs to run regardless of some of these being down).
I would expect declared exceptions to be at the same level of abstraction as the interface/methods defining them. e.g. a TradeStore would be declared to throw a TradeException, not a SQLException (since methods of storing a trade are an implementation of TradeStore - you could store in a relational db, a JavaSpace etc.).

As a warning, when displaying lower level error messages to users, make sure they're sanitized of system information. This is an area where many security exploits originate. Log them with full information, but only display a more general error message to the user.

Related

Using exception for communication

I have heard that one should not use exception for communication.
I have a scenario that I would like to discuss.
We have a rest controller that invokes a service that is responsible for fetching a product from the database. Currently if product can't be found we will get an exception (checked exception) productNotFoundException.
This exception goes all the way to the controller. In the controller we have a controller exception handler (controller advice) that takes care of the exceptions and returns 404.
I was told that if they are run on different threads then the whole application would crash and it would be better to deal with the exception directly. Currently a lot of methods are being called and all have throws prodNotfoundex.
Can some one explain why it would crash. My project is a spring boot project.
I was told to return an empty response to the controller instead of throwing an exception.
I'm not sure how it would crash your application, if you handle/catch the exception properly.
Regarding exceptions, it should be seen as an exceptional state -- that is not in the normal flow of actions. Eg. the FileNotFoundException is exceptional, because you wanted to open the file, but it's not there. You expected it to be there, but it wasn't.
If you search for a product, you don't expect it to be there in the general sense of "expecting to find a loaf in the grocery store". You searched for a bunch of keywords, and the search resulted an empty response/zero matches. It is not exceptional in your business logic.
On the other hand, when you click "order" on a product (say on the product page), and then the product is not found, it is "exceptional". You expected a product you found 2 minutes ago to be there, but it isn't any more.
Some links on Java Exception handling costs:
http://java-performance.info/throwing-an-exception-in-java-is-very-slow/
Is it expensive to use try-catch blocks even if an exception is never thrown?
How expensive are Exceptions
How slow are Java exceptions?
Decide it for yourself.

When to log chained exceptions?

I am a green developer trying to get a handle (har-har) on error handling in a large multi-layer java application. There are many situations where I believe that chaining exceptions through several layers is a good idea; e.g. when a failure in calling out to some external service at the lowest layer causes problems all the way up in the view:
Content X requested, but user isn't authorized
caused by: List of authorized users is null
caused by: User-management webservice responded Bad Request- Parameter foo must be formatted like 'xyz'
The most important exception, the one whose stacktrace I really want to examine, is the last in the chain; that I made a bad request and I need to fix foo's formatting. But when I let this exception bubble up through the layers, nicely chained in exceptions that are meaningful to each layer... when I eventually catch and log the thing, the default logging behavior always shows me gobs of detail about the outermost exception, and maybe 5 lines of stacktrace of the root cause.
This makes me want to log exceptions as they happen, AND let them bubble up, but then you end up logging most things twice; when they happen and when they are eventually caught.
What is the best practice here?
I would recommend a different approach of exception management. At the top most layer of the application (like request entry point) create a try catch block to call any runtime exception. It's preferable that you have 2 catch blocks:
- for your application specific (business) exceptions
- for the rest (exception)
As you can see youl'l need to introduce you own exception type that you'll extend to create different exceptions for different purposes. For example you can create a custom exception for every layer of the application, for each integrarion etc. Use unchecked exeptions as they all will be handled on the top level. When any exceptional situation ocures (catch of low level exception) you should:
- Put a description associated with the business context (for example "failed to load account data from DB"
- Add description of the original exception (for example "Original error: Connection to DB failed")
- Pass original exception to your exception in order to not loose the trace
- Throw and forget. In other words top level catch block is responsible to handle it appropriatelly (rollback a transaction, show error message or anything else you may need
Great question, I'm curious about other answers you will get.
I tend to take a "more is better" approach, and log at each step of the way. Does this make large logs? Yes, but when you're debugging an issue in a large Java application, you will be thankful for every log line you have. There are also tools (at the very least the grep, awk, sed trio) to help you filter through large files.
Another technique is to write this logging code, but turn it down (if you're using something like log4j, to the TRACE level). This way, should you run into an issue, you may not have the logs available, but it's a one line change (to lower the logging threshold) and you start generating a wealth of data for debugging.
In tandem with the previous technique, most logging libraries (again I'm falling back on my knowledge of log4j here) allow you to tune the log levels of different java packages. This means that you can write all of these "catch and rethrow" log lines as trace, and turn down the logging on lower level packages to WARN while you keep upper level packages at DEBUG or TRACE.

Always try-catch-finally for exceptions? Central error management?

I wonder if I always have to use try-catch-error blocks that clutter the code a lot, if I want to catch an error.
Or can I somehow define a global error catcher?
Especially regarding Java EE Webapps.
For every unhandled ex I'd like to log to a specific file, and display a general error page to the user.
I thought I might achieve that with aspects. But for aspects to catch on #AfterThrowing, I too have to introduce try-catch blocks. And as there is no central class for the backing-facades, I would have to surround every backing method with trycatches.
Then the aspect would take them, but I need something to catch without explicit throws exceptions.
How could I to that?
You are looking for the declare soft construct. This will wrap the given exception in a SoftException (an AspectJ-specific RuntimeException) so that it does not need to be explicitly handled. Then you can handle all of these exceptions with some AfterThrowing advice.
declare soft only exists in code style AspectJ (ie- there is no annotation for this). So, you will need to compile your code using the AspectJ compiler, but you can still use load-time weaving for this if you like.
See here:
http://www.eclipse.org/aspectj/doc/released/progguide/quick-other.html
And here:
http://www.eclipse.org/aspectj/doc/released/adk15notebook/declare-soft.html
Here's a code snippet that shows how it can be done:
aspect ErrorHandler {
declare soft : Exception : within(*);
after() throwing(Exception e) : handler(e) {
// do something...
}
}
This will route all exceptions in your system through your custom error handler. And you won't need to explicitly catch or throw them.
It's simple and powerful. Perhaps too powerful, though. I'd recommend refining and being more precise about exactly which exceptions should be softened and which ones need to be advised, but this is the basic idea.
You don't have to do this in every method.
You should not catch an exception that you can't "handle". Handling means more than just rethrowing or logging or printing a stack trace. I think handling means implementing a meaningful recovery strategy.
It might mean "the buck stops here": You're Gandalf on the bridge at the edge of a layer boundary, and no exception shall pass. You don't want users to see nasty messages, so you catch and route them to a friend, easy to understand page that tells them what to do next.
Finally isn't always necessary, but it's perfect for cleaning up resources like file handles and database cursors.
If you cannot handle an exception, there's no shame in adding the throws clause to the method signature and letting callers figure out what they want to do.
In the general case, there is no mechanism to do this - Java does not have what you're looking for.
However, depending on your circumstances, it might be possible.
web.xml Exception Handler
The web.xml file allows you to define a URL to be used to handle specified exception type. (See, for example, http://wiki.metawerx.net/wiki/Web.xml.ExceptionType).
Since you're writing a webapp, you may be able to just let the exceptions throw all the way to the top, and then handle them this way.
Custom interceptor
You mention that you have backing-facades. Depending on how they're being constructed, you may be able to put a generic proxy in front of them to catch and handle the exceptions you're interested in. You've tagged your question with spring, to you might want to look at Spring AOP Proxies.
There might be other ways to get what you want, but it will depend on the specifics of your application's architecture.
The finer control you have of the exceptions, the easier it will be to debug/provide a meaningful message.
To which extent? I would link that to the complexity / expected lifetime of your application. The bigger those are, the finer should be your handling.
I see two main approachs:
User approach: You get at least one exception handling for each UI action (so you can say: "Do not push that button AGAIN").
Debugger approach: Every method has its control.
Keep in mind that most handling could be just logging of rethrowing of the exception.
More to the point, most probably, your Java EE framework will have log options in its configuration files (many of them working with java.util.loggin or log4j). You could tweak that; of course, what is send to each log category will depend of the framework implementation (so maybe not all ERROR messages will be Exceptions).

how to handle hibernate exceptions

I have few questions like
Which is the right place to handle a Hibernate RuntimeException.
DAO Layer?
ServiceLayer?
For instance, I have saveCustomer and the transaction fails, how can I inform the user through Exceptions?
I'm using the OpenSessionInView pattern, which will commit the transaction only after the view is rendered. In this case, if the transaction fails, How can I inform the user about this?
Generally it's a good idea to handle exceptions at the point in your code where you have the most information on how to handle them (or generate an appropriate error message with enough information). In the j2ee apps I've developed I usually have a transactional service layer that stitches together various DAO calls and I usually handle hibernate-specific runtime exceptions and all other data-related exceptions in the service layer. That said, if there's a pile of logic within a DAO where something bad could go wrong, it's probably not a bad idea idea to catch it there, add some error message context, and then rethrow it up the chain.
If an exception happens within your transaction you can either leave it uncaught or rethrow it with some additional context. This way your transaction manager knows to rollback the transaction. Always have an exception handler set up in your view/controller layer to handle any application-specific runtime exceptions that were thrown from your service layer calls. Inspect them for additional error messages and then use them to inform the user appropriately.
As far as I know, the default behavior when an exception is thrown out of a transaction it should rollback and not get committed at all. The answer to #2 really answers this one as well, i.e., if you've wrapped all your view layer's service calls in try/catch blocks or configure one globally via your web framework you shouldn't have a problem notifying the user that something bad-wrong happened.
This article (Best Practices for Exception Handling) has a decent overview on exception handling in general that you may also find useful.
Catch the exception where you can do something with the exception. If you catch it in DAO layer, then the information specific to dao layer needs to be extracted. e.g. if it is can not insert null value, then log the field details where it is failing. Once done, then the service layer can do business related processing of the exception directly or in wrapped format. You can see these common mistakes in exception handling. This is not applicable to specific hibernate example but in general to all.

what is preferred approach to return business validation results in business layer

Let's assume we have a client application (either web or standalone) which uses kind of business layer (EJB, Spring services etc). Let's say user wants to execute some business logic (e.g. create something). This operation has some preconditions like data format, existing of other objects in DB, permissions etc. Now what is the best design of this business logic layer, I mean how to return validation errors, indicate success, return unexpected error etc?
Ways I know:
1)
for validation errors return e.g. OperationResult object having status and list of violations,
for success: OperationResult with status=success and empty errors list,
for unexpected errors throw runtime exception
2)
for validation errors throw ValidationException (runitme or checked?) having list of violations
for success: void or created entity if required
for unexpected errors throw runtime exception
There are two basic ways I know but every time I start writing I have hard time to get it right.
I have an aversion for the validation exception method, after all there is nothing exceptional in a validation error, so I find it hard to justify to use an exception for that. So on a theoretical basis the only valid option is the first one.
Having said that, although it depends on what validation framework you're using*, but it's usually much easier to code the exception version.
Whether your validation exception (if you're using one) should be checked or not opens up another can of worms, some people are very much against checked exceptions in general, others will say the exact opposite. For my two pennies worth I believe that runtime exceptions should be reserved for coding errors and an "expected" exception should be checked, whenever that's possible. But I have to stress that this is just personal preference on my behalf.
*If you have multiple validators that will all have to be run in a validation phase, exceptions are not very effective. If you intend to stop at the first failed validation step, exceptions are easier to implement and probably more readable.

Categories

Resources