Click here to Skip to main content
15,881,139 members
Articles / Programming Languages / Java

Exception handling framework in Java

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
30 Apr 2017CPOL5 min read 18K   318   5   1

Introduction

In java it is very easy to handle exception , by adding try-catch-finally block. For simple application or testing purpose it is ok. But while you are thinking of working on an enterprise application then you could understand that you need some well structure code to habndle this in a better and efficient way. In this article I am trying to explain how to handle exception in a better and managed way.

Background

In traditional approach there are so many issues you could face while working on enterprise application.
Initilay it is very hard to identify the problem. But while the volume of the application is increase, you could understand that.
Below are the key factor :

1. Manitainability : Often you can see that , same type handler code has been written for different type or same type of exception. It is very hard to keep track if any changes required. So maintaining the code itself is a big challenge for a modular base application.

2. Reusability: If purpose is the same then why shouldn't we use the same piece of code for different exception.As discussed in point 1, it is also decrease the chance of reusability for same purpose.

3. Plugable & Flexible: Today hadnler codes only job to log the exception. In future, may be need to sent mail or need to post that in some jms queue or need to do some rollback task or may be required to do all the task or may be the combination of the task. In normal approach , it is almost imposible to alter the code on demand because handling codes are tightly couple with the source of exception.

4. Readability: Often see, catch blocks itself conatins some complicated code which not only increase the lenght of the method and also decrease the code readability.

5. Easy to Use: In legacy application, sometimes ,it is very tough to track down the exception handling. In trdationl approach you have to spend enough time to understand the flow.

Above issues are very common and everybody have faced those issue once.

The key strategy behind this framework is to separate the handler logic from the source of exception to make the relation as lossely couple and hook this hadnler when needed. Separating the handler logic is not so big deal . we can create a handler class and keep the logic inside it. But the main concern is that how to hook it so that it wil increase the reusability, maintainbility, flexibilty and simple too. Here we go.

Lets take the following simple example :

Java
public void  checkLogin() {
     try  {

         //Statement 1 which may throw  new UserNotExistException("User not Exist.");

         //Statement 2 which may throw new InvalidCredentialException("Invalid Credentials.");

         //Statement 3 which may throw new DBException("Failed to retrieve data.");

         //Statement 4 which may throw new Exception("General Exception.");

     } catch (UserNotExistException uex) {
         //To do
     } catch (InvalidCredentialException fex) {
         //To do
     } catch (DBException dex) {
         //To do
     } catch (Exception ex) {
         //To do
     }
 }

Above example is very simple one to validate the user. We can see that this method may throw 4 types of exceptions (in real world it may be different). There are also some catch blocks to catch those exceptions. We are very familiar with such type of scenario.

As per the requirements, if there are any exception occoured,application may take the following handler actions (single action or combination of actions)to handle each type exception : (For example purpose I have taken 4 handler actions)

  1. want to log exception
  2. want to send error details to some jms queue
  3. want to send mail
  4. want to do some default work

Now rewrite the catch block by adding the above handlers

Java
public boolean checkLogin() {
    try  {

        //Statement 1 which may throw  new UserNotExistException("User not Exist.");

        //Statement 2 which may throw new InvalidCredentialException("Invalid Credentials.");

        //Statement 3 which may throw new DBException("Failed to retrieve data.");

        //Statement 4 which may throw new Exception("General Exception.");

    }  catch (UserNotExistException uex) {
        //To do

        // want to log exception
        // want to do some default work

    } catch (InvalidCredentialException fex) {
        //To do

        // want to log exception
        // want to send mail
        // want to do some default work

    } catch (DBException dex) {
        //To do

        // want to log exception
        // want to send error details to some jms queue
        // want to send mail
        // want to do some default work

    } catch (Exception ex) {
        //To do
        // want to log exception

    }
    return <some_flag>;
}

When you working in a module base application, you could understand the pain to maintain the codebase. Now take the following example which is doing the same thing as the above example but in an effective way.

Java
@HandleExceptions({
    @HandleException(exceptionType = UserNotExistException.class, handlers = {
         "logExceptionHandler","defaultExceptionHandler"
    }) ,
    @HandleException(exceptionType = InvalidCredentialException.class, handlers = {
        "logExceptionHandler", "sendEmailExceptionHandler", "defaultExceptionHandler"
    }) ,
    @HandleException(exceptionType = DBException.class, handlers = {
        "logExceptionHandler", "JMSExceptionHandler", "sendEmailExceptionHandler", "defaultExceptionHandler"
    }) ,
    @HandleException(exceptionType = Exception.class, handlers = {
        "logExceptionHandler"
    })
})
public void checkLogin() {
    //Statement 1 which may throw  new UserNotExistException("User not Exist.");

    //Statement 2 which may throw new InvalidCredentialException("Invalid Credentials.");

    //Statement 3 which may throw new DBException("Failed to retrieve data.");

    //Statement 4 which may throw new Exception("General Exception.");
}

If we ignore the anotation part(coming later), one can easily understand that it is very simple and more clean one than the above example. You can see that there are no catch blocks inside the method body. Now the method is more clear and readable and it is only focused on what it is intended to do.
Now start digging the codebase to understand the framework. I have created this framework on top of Spring framework.

The key idea behind this framework is that intercept an exception after it’s thrown, but before it’s caught and do the needfull action as required. To acheive this , I have used Spring AOP @AfterThrowing advice in a Spring application. (If you are not familiar with AOP(Asepect Oriented Programing), then go to http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html ).

Into the depths

Now it is time to look into the code base. There are three user defined annotation inside the com.sm.exceptionhandler.annotation pacakge.

  • Handlers.java
  • HandleException.java
  • HandleExceptions.java

There are two way to bound handler with exception in this framework. One is :

Handlers.java: Used to annoted a custom exception class to register with default handler(s).

C++
@Handlers({"fileExceptionHandler", "defaultExceptionHandler", "logExceptionHandler", "JMSExceptionHandler"})
public class UserNotExistException extends BaseException {

and the second onr is :

HandleException.java: Class which may throw exception(s) must be annoted with this annotation.

C++
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface HandleException {
    static final String DEFAULT_HANDLER = "defaultExceptionHandler";
    public Class<?> exceptionType() default Exception.class;
    public String[] handlers() default {DEFAULT_HANDLER};
}

It has two properties. To respond on a specific exception ,user need to mention the type of exception as exceptionType and the list of handlers to react on this exception. Here handlers are Spring bean id. One can mention multiple handlers for a specific exception.

If there is a possibility to get multiple type of exception and you want to handle them individually then exceptionType param will help you to solve this problem.

You could use the following code to handle multiple type exception

C++
@HandleExceptions({
     @HandleException(exceptionType = FileNotExistException.class, handlers = {
         "defaultExceptionHandler", "logExceptionHandler",
         "JMSExceptionHandler"}),
     @HandleException(exceptionType = UserNotExistException.class, handlers = {
         "logExceptionHandler", "JMSExceptionHandler"})
})
public Integer testExceptionOne(int type) {
}

Or you can write the most simple one which will act on each exception.

C++
@HandleException(handlers = {"fileExceptionHandler",
        "defaultExceptionHandler", "logExceptionHandler"})
public void testExceptionTwo() {
    throw new RuntimeException("Io Exception");
}

HandleException.java: Contains list of HandleException.

HandleExceptionAspect.java is the aspect which basically weaving at runtime with the application. Using @AfterThrowing, aspect can able to execute the advice only when exceptions of a given type are thrown, and also able to access to the thrown exception in the advice body.

ExceptionHandlerFramework.java Contains the main logic to call and process the respective handler.

Rest of the java classes are very straight forward and are self-explanatory.

Points of Interest

It is very simple and easy to use

Keep in Mind

Attached code base is a netbeans project and tested in java 1.7 .

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
India India
Make the world open source

Comments and Discussions

 
QuestionError in running tests code Pin
Devesh Singh31-Oct-18 4:36
Devesh Singh31-Oct-18 4:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.