An Exception Handling Framework for J2EE Applicationsby ShriKant Vashishtha
In most Java projects, a large percentage of the code is boilerplate code. Exception handling comes under this category. Even though the business logic may be just three or four lines of code, exception handling might go on for ten to 20 lines. This article talks about how to keep exception handling simple and straightforward, keeping the developer's plate clean for him to concentrate on business logic rather than devoting time to writing exception-handling boilerplate code. It also gives the basis and guidelines to create and deal with exceptions in the J2EE environment and targets some of the business problems, in which exceptions could be used to resolve them. This article uses the Struts framework as the presentation implementation, though the approach is applicable to any presentation implementation.
When Do We Need Checked and Unchecked Exceptions?
Have you ever wondered why it is such a pain to put a
catch block around a block of code you have written, even if you know that you cannot do much about those exceptions and will be content with just logging them in the
catch block? You may wonder why this can't just be logged in a centralized place, which in most cases for a J2EE application is a front controller. In other words, you would like to not be bothered with them, as you don't have much to do with them. But what if a method signature contains a
throws clause? You are either forced to catch these exceptions or put them in a
throws clause of your own method. That's a pain! Fortunately, the Java APIs have a category of exceptions called unchecked exceptions, which you are not forced to catch. Still, the question is, on what basis do you decide which exceptions should be checked and which unchecked? Here are some guidelines:
- Exceptions for which the end user cannot take any useful action should be made unchecked. For example, exceptions that are fatal and unrecoverable should be made unchecked. There is no point in making
XMLParseException(thrown while parsing an XML file) checked, as the only action to be taken may be to fix the root cause based on the exception trace. By extending
java.lang.RuntimeException, one can create custom unchecked exceptions.
- Exceptions associated with the user's actions in an application should be made checked. Checked exceptions require the client to catch them. You might ask why we don't make every exception unchecked. The problem might be that some of them may not get caught where they should be. It creates a bigger problem as errors are identified at runtime only. Examples of checked exceptions are business validation exceptions, security exceptions, etc.
Exception Throwing Strategy
Catch a base application exception (say,
BaseAppException) only and declare in your
In most of J2EE applications, decisions about what error message to show on which screen against an exception get made in the presentation layer only. This brings up another question: why shouldn't we put this decision making in a common place? In J2EE applications, a front controller is a centralized place to do common handling.
Also, there has to be a common mechanism to propagate the exceptions. Exceptions need to be handled in a generic way, too. To deal with this, we always need to catch the base application exception
BaseAppException at the controller end. This means we need to put the
BaseAppException, and only that exception, in the
throws clause of each method that could throw a checked exception. The concept is to use polymorphism to hide the actual implementation of the exception. We just catch
BaseAppException in the controller, but the specific exception instance thrown might be any of several derived exception classes. You get a lot of exception-handling flexibility using this approach:
- You don't need to put so many checked exceptions in the
throwsclause. Only one exception is required in
- No more clutter of
catchblocks for application exceptions. If we need to deal with them, one
BaseAppException) is sufficient.
- You don't need to do exception handling (logging and getting the error code) yourself. That abstraction will be taken care of by
ExceptionHandler, which will be discussed later.
- Even if you introduce more exceptions into the method implementation at later stages, the method signature doesn't change, and hence requires no change in the client code, which otherwise would have to be changed in a chain reaction. However thrown exceptions need to be specified in the Javadoc of the method so that the method contract is visible to the client.