Checked Exception, Java 5 Annotations: A Proposal


While Commons BeanUtils is one of the most useful components in Jakarta Commons, it does require a great deal of exception handling madness to accomplish some very simple tasks. Take, for example, copying bean’s properties from one instance of a bean to another. Since BeanUtils throws checked exceptions, almost all code that deals with beans in a dynamic manner is full of try/catch blocks. Here’s a simple code snippet: it should be one line of code, but is 8 because of the required exception handling.

    try {
       BeanUtils.copyProperties( blah, blah2 );
   } catch (IllegalAccessException e) {
 e.printStackTrace();
   } catch (InvocationTargetException e) {
 e.printStackTrace();
   }

Explicitly catching these exceptions is a waste of development time. I’ve been surrounding most of my calls to BeanUtils with a catch for Exception, throwing a RuntimeException if something goes wrong in BeanUtils. For the code I’m working with, an exception involving BeanUtils is something I’d catch in a unit test. In other words, it is well within reason to ignore these exceptions. In general, I catch checked exceptions and handle errors appropriately when possible. If, I’m trying to access a bean property that doesn’t exist, I’m usually wrapping Exceptions from BeanUtils in an instance of RuntimeException and flagging such an event as a fatal system-level event. I wish there was a way in Java 1.5 to annotate methods such that specific exceptions could be flagged as RuntimeExceptions. Instead of requiring a developer to catch a checked exception, you could just mark a method (or a class) with an annotation which would declare a specific exception (or all checked exceptions) as runtime exceptions.

Change the Language: I’d like to type less…

In other words, I want a mechanism that would allow you to ignore checked exceptions at the method level. Checked exceptions are valid in some cases, but there should be some sort of option available to selectively ignore the check for specific Exception types. Instead of telling me that I have to deal with an IOException when opening a File, let me turn it into a RuntimeException at my own risk. Let the API designers make recommendations, but let the people who actually use the API have the final say as to whether a particular thrown Exception really needs to be checked or not. In other words, let me use BeanUtils the way I want to use it, without requiring four catch blocks every time I try to read a bean property. Trust the end-user. I’m sure that the code that controls the Shuttle’s solid booster rocket needs to catch every single exception thrown, but my simple, one-off Java program to print the quote of the day can safely ignore all checked exceptions. Allowing people to turn off checked exceptions would significantly reduce code bloat.

I’m looking for two things: the ability to declare the exceptions a method could throw and specify how those exceptions are thrown – checked vs. runtime and a way to selectively ignore checked exceptions. Here, take a look at this, I’ve taken exceptions out of the method signature and created a (fictional) annotation. This fictional annotation not only defines the type thrown, but (most importantly) defines this as an unchecked IOException. The exception would be thrown in the same way you would throw an IOException today, but the annotation allows you to specify runtime vs. checked.

    @Exception( type=IOException, checked=false )
   public void doSomething() {
       File f = new File( "blah.txt" );
       InputStream is = new FileInputStream( f );
       is.read();
       // ... stuff ...
   }

If a method throws an Exception, it should be declared as an Annotation. This annotation would allow for a richer specification of exactly how and when an exception is thrown. Who knows? there could be things one could specify like whether a specific Exception type halts a JVM or the name of a method to be called in case a specific method is thrown. Instead of relying on extension to define which exceptions are runtime vs. checked, different exceptions could be exposed as runtime exceptions depending on the attributes of an @Exception annotation on a particular method. A generic, widely used API such as Commons BeanUtils could still define all exceptions as checked exceptions.

This still doesn’t solve the problem of being able to selectively ignore checked exceptions. If a component throws checked exceptions, I want to be able to automatically wrap them in a RuntimeException. For example, the following annotation would wrap any checked exception that occured in the method body in a RuntimeException.

    @WrapException( type=Exception, wrap=RuntimeException )
   public void doSomething() {
       BeanUtils.copyProperties( blah, blah2 );
   }

You might be asking yourself why it would ever be a good idea to allow people to “ignore” exceptions. First, I’m not advocating that people ignore exceptions. Exceptions are a useful way of signalling errors and unexpected problems. Exceptions should be dealt with properly, and everyone writing good code should go to great length to handle exceptions that can be handled. My problem is that, for most of the systems I develop, my unit tests assure that my calls to BeanUtils.getSimpleProperty() will never cause an IllegalAccessException, or my calls to Betwixt’s BeanReader will never cause an introspection-related checked exception to be thrown. If the execution environment of my code was not under my control, I’m sure I’d want to catch all of the exceptions thrown by BeanUtils, but in my current situation it is more of a distraction than anything else.

In a broader sense, I think that the whole approach to Java exceptions needs some fresh thinking. Right now, exception handling in Java still makes me cringe. I dislike the fact that I can’t group collections of exceptions together in catch blocks, and I’m ready for exceptions to be declared using annotations. I’m happy with the way that Spring allows you to declare Transaction boundaries using Annotations, and I’m ready to write far fewer try/catch statements than I do today.