Exception Handling API


Even though Java is out there for 20 years, Java developers are still facing problems implementing the exception handling in the most proper way in order to make it re-usable, encapsulated, centralized, and pluggable. In this section, we propose an API design and implementation for exception handling toward making the exception handling more robust and efficient.

For detailed description about this API, check my aarticleion Handling in Real-Life Java Applications” on DZone.

API-usage by example

Assuming we want to handle FileNotFoundException, in traditional way, it would be something like this:

package com.jalalkiswani.example;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class FileReader {
    public void loadFile() throws FileNotFoundException {
       FileInputStream in = new FileInputStream("file-not-found.txt");
    }
}

 

package com.jalalkiswani.example;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionTest {

    public static void main(String[] args) {
    try {
      ExampleFileReader reader=new ExampleFileReader();
      reader.loadFile();
     } catch (FileNotFoundException e) {
       e.printStackTrace();
     }
  }
}

Now, assume this has been called across the whole application (e.g. in 200 classes), and in later phases, the business has changed to handle the exception by showing a Swing message, this would be very costly.

In our proposed API, the developer can handle such exceptions all the time by just calling JKExceptionUtil.handle(s) as follows:

package com.jalalkiswani.example;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import com.jk.exceptions.handler.JKExceptionUtil;
public class ExampleFileReader {
   public void loadFile() {
   try {
      FileInputStream in = new FileInputStream("file-not-found.txt");
      System.out.println("Not reachable");
   } catch (FileNotFoundException e) {
      JKExceptionUtil.handle(e);
   }
 }
}

In the previous example, the developer doesn’t need to handle a specific exception; Rather he/she only catches the Exception class, and calls JKExceptionUtil.handle(e) in the catch clause. In this case, it will call the default exception handler, that also prints the stack trace by default, then throws a runtime exception, wrapping the original exception inside.

Custom exception handler

Now, say we want to handle this exception in an appropriate way by showing a Swing message, logging the exception and throwing a runtime exception, wrapping the original exception in. We create a custom handler class that implements the JKExceptionHandler Class with the generic parameter FileNotFoundException, as follows:

package com.jalalkiswani.example;
import java.io.FileNotFoundException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import com.jk.exceptions.handler.JKExceptionHandler;

public class FileNotFoundExceptionHandler implements JKExceptionHandler<FileNotFoundException> {
Logger logger = Logger.getLogger(getClass().getName());

   public void handle(FileNotFoundException throwable, boolean throwRuntimeException) {
     JOptionPane.showMessageDialog(null, "The file your requested is not found");
     logger.log(Level.WARNING, "File not found : ", throwable);
     if (throwRuntimeException) {
        throw new RuntimeException(throwable);
     }
   }
}

Next, we will register this handler during application startup in a static initializer as follows:

package com.jalalkiswani.example;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import com.jk.exceptions.handler.JKExceptionHandlerFactory;
import com.jk.exceptions.handler.JKExceptionUtil;
public class ExceptionTest {

  static {
    JKExceptionHandlerFactory.getInstance().setHandler(FileNotFoundException.class, new FileNotFoundExceptionHandler());
  }
   
   public static void main(String[] args) {
      ExampleFileReader reader = new ExampleFileReader();
      reader.loadFile();
  }
}

By registering this exception handler, this handler will be called every time by ExceptionUtil.handle(e) if the exception instance is of type FileNotFoundException. It is recommended the handlers are set in the application bootstrapping phase, in the main class in the case of native applications (i.e. desktop, console, or mobile), or in context listeners in the case of web and enterprise applications.