So, Java checked exceptions. Of all the Java hot-points, this one still has the power to invoke avid flame wars between those who feel they make the platform “enterprise” class and those who are so disgusted with writing try/catch blocks to wrap them that they are willing to defect to .Net & C# simply to escape the drudgery of it all (.Net does not have checked exceptions).

Now, to be honest, while I have tried to look at the issue from multiple perspectives over the years, I tend to find myself leaning toward the latter camp for one very simple reason:

“Checked exceptions are great in theory, but in practice lots of developers use them poorly and then the rest of us are left to clean up their mess.”

Truthfully, as a developer that’s somewhat par for the course, you get used to paying for the mistakes of other developers and to be honest I know that when pressed for time I’ve written less than stellar code that I’m sure someone else has had to clean up. It’s just part of being a developer.

However, the problem with checked exceptions is that when they are done wrong you suffer in really really ugly ways that take your suffering to completely new levels. In this article I’m going to first cover some of the various problems that exist with using checked exceptions and then… for the finale, I’m going to show you a technique I’ve started using in the ThinWire Ajax framework and other projects to force checked exceptions into behaving like plain old RuntimeExceptions. Yup, you read that correctly. If you just can’t wait to see how that’s possible, you can jump to the end.

Adventures with java.sql…

To get started, the most common way checked exceptions make you suffer is when you are forced to deal with an API that has chosen to throw checked exceptions whenever anything at ALL goes wrong. A classic and widely known example of this is the java.sql API. I’ve been fortunate enough to avoid having to write much code against that API and when I have had to use it, I’ve usually developed a pattern that makes working with bearable. However, as I mentioned, the real problem is not necessarily the code you write, it’s the code other’s write and I know I’ve seen one too many code blocks that look like this:

A real-life in the wild example

public void testRetrieval() throws SQLException, IOException {
    try {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
    } catch (java.lang.ClassNotFoundException e) {
        System.err.print("ClassNotFoundException: ");
        System.err.println(e.getMessage());
    }
 
    try {
        Connection con = DriverManager.getConnection("jdbc:odbc:test",
                "user", "password");
        System.out.println("Connection To The Database Established...");
        stmt = con.createStatement();
    } catch (SQLException ex) {
        System.err.println("Connection SQLException: " + ex.getMessage());
    }
}
 
public Info getData(String rNum) {
    Info info = new Info();
 
    try {
        ResultSet rs = stmt.executeQuery("select * from itable where po ="
                + rNum);
 
        if (rs.next()) {
            info = getResultSet(rs);
        } else {
            // do nothing
        }
 
        rs.close();
    } catch (SQLException ex) {
        System.err.println("SQLException: " + ex.getMessage());
    }
 
    return info;
}
 
public Info getResultSet(ResultSet rs) {
    Info info = new Info();
 
    try {
        info.setPo(rs.getString("po"));
        info.setType(rs.getInt("type"));
    } catch (java.sql.SQLException se) {
        System.out.println("Info retrieval from ResultSet failed." + se);
    }
 
    return info;
}

That’s a little bit clearer don’t you think? The more savvy of you might be balking at the lack of proper Statement & ResultSet closing within a finally block, but keep in mind that the developer wasn’t doing that anyhow and additionally the use of a finally block has nothing to do with the handling of checked exceptions.

Different Recovery Strategies

Now, I want you to consider something else about this code. What do you suppose you could do to reasonably recover from an exception being thrown by any random java.sql method? Lets see:

Option 1: You could retry the whole block I suppose, but without extensive investigation of the SQLException details and a solid understanding of the error states presented by the specific DB you are connected to, that would really just be a shot in the dark.

Option 2: You could log all the exception details so that it’s easier to troubleshoot. But wait, wouldn’t it make sense to handle that in a centralized place further upstream in your code? Oh, I know… throw another exception that your upstream code catches! Although that’s somewhat repetitive when you think about it. You catch an exception just so you can throw it upstream. Hmm.

Option 3: Well, I guess you could log the details and return a default empty value or default object and then your upstream code could still process the empty value, but that seems kind of senseless. You’d either have to write your upstream code in such a way that it made sense to process an empty value or you’d have to write it to detect the empty value and treat it like an error has occurred. But wait, wouldn’t that kind of put you back into the same mode of development that used to exist prior to exception handling in languages? The kind of development where you always have to check the return value to see if an “error-value” was returned. I shudder at the thought!

Handling Checked Exceptions Sensibly

So, hopefully you see what I’m saying here. Generally, there is very little you can do to sensible respond to an SQLException, at least not that close to the SQL code. This leads me to Option 4, which is hardly ever used, but is in fact the most appropriate way to handle this case: Declare your SQL processing method declarations with “throws SQLException” on the end. The theory here is that somewhere up the call stack, in code that the SQL processing methods do not know about, there is a place in the application where the current “Operation” began and it is at that point in the application that you can generally handle an exceptional situation the most gracefully.

For instance, a web application may receive a request to display a specific record. In response, the application prepares a pretty HTML view that contains a number of sections, such as a header, footer, navigation, top-level record information and finally the specific details of an item. To assemble all of the information, the view will likely call out to entity objects, other framework layers or at the very least other methods to retrieve the data records. Whatever the structure, the point is that it’s in the view presentation code that it’d make most sense to setup a try/catch and often times that’s a few method calls removed from the SQL code. In the simplest case you could just wrap the whole body in a try/catch, excluding the header/footer/navigation sections, and then if a failure occurs you could display an error message in the body while still allowing the user to attempt to navigate to other parts of your application.

Third-Party API’s Prevent Elegant Handling

Unfortunately, even if the developer gets smart and decides to try something like this, they often times run into another major issue with checked exceptions. Declaring that a method throws a checked exception, binds the method that calls it to the contract of either handling the checked exception or declaring that it also throws the exception. So by placing “throws SQLException” on all the methods, you’d be forcing all upstream users of your API to handle the SQLException in some way. At first the solution may sound straight forward. Just have all upstream methods declare “throws SQLException” and then the exception will unroll up the call stack to the desired spot.

It’d be great if that worked, but often times there are road-blocks in that wonderful idea. The primary one being that you most likely don’t have control over every single method declaration. Often times a layer of your code implements an interface from a third-party library and the interface probably doesn’t throw SQLException or whatever checked exception type you need to pass up the call stack. So, what do you do. You’re stuck. Well, if you’ve ever found yourself in this situation, you do the only thing you can (unless you use the technique below). At the interface method implementation, you wrap the checked exception in a RuntimeException and throw it up the call stack. Talk about ugly!

Rethinking the Value of Checked Exceptions

About this time you should be trying to reassure yourself that checked exceptions are a good thing and that such issues are just part of creating highly robust code. Ok, hopefully you’re not saying that, because again, ask yourself: What do you suppose you could do to reasonably recover from an exception being thrown by any random java.sql method?

Answer: Very Little. Keep in mind I said “reasonably recover”. Remember, that is in fact the purpose of checked exceptions. If the operation cannot be reasonably recovered from then the API should be throwing unchecked exceptions. In the case of the SQL API, there is very very few cases where a reasonable recovery is possible and even if you could dream up a recovery scheme, it’d probably be very costly to implement and unreasonable for 95% of the applications. And when you think about it, many API’s that use checked exceptions do so improperly. java.io? Hmm… IOException… couldn’t read from my file. What can I do to recover from that within the context of my file read method? Nothing.

What About Mission Critical Applications?

But what if you’re writing a 100% mission-critical cannot go down under any circumstance or else I’ll loose my job and life kind of application? The kind of application that runs the Mars Rovers or the New York Stock exchange or eBay. Well, great, invest in redundant servers, clusters, backups, replication models, use transactions, do extensive unit testing, end-user testing, stress testing, and apply sensible exception handling. But checked exceptions will not in anyway determine your success or failure.

Ok, ok. Enough on that. If you still think checked exceptions are great then no one will convince you otherwise and I’m sure the following code will really make your blood boil.

How-To Bypass Checked Exceptions

Recently I checked in a class called Reflector to the thinwire.util package of the framework’s dev trunk. One of the static methods on it has the signature:
public static void throwException(Exception e);

It’s intended to be used in the following manner to first catch and then re-throw a checked exception in a manner that bypasses the checking that both compiler and byte code verifier do to make sure that checked exceptions are handled properly. Here’s how you might adjust the prior example to leverage the checked exception bypass:

public void preformOperation() {
    // You can simply call the retrival method without a try/catch
    testRetrieval();
 
    // Or you can wrap it in a try catch to catch the checked exception
    try {
        testRetrieval();
    } catch (Exception e) {
        if (e instanceof SQLException) {
            // do something
        }
    }
}
 
// Assuming testRetrieval is the public API boundary
public Info testRetrieval() {
    try {
        Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
        Connection con = DriverManager.getConnection("jdbc:odbc:test",
                "user", "password");
        System.out.println("Connection To The Database Established...");
 
        stmt = con.createStatement();
        Info info = getData(1);
        return info;
    } catch (Exception e) {
        // Calls the special method that bypasses checking
        throwException(e);
 
        // Unreachable code
        return null;
    }
}
 
private Info getData(String rNum) throws Exception {
    Info info = new Info();
    ResultSet rs = stmt.executeQuery("select * from itable where po ="
            + rNum);
 
    if (rs.next()) {
        info = getResultSet(rs);
    } else {
        // do nothing
    }
 
    rs.close();
    return info;
}
 
private Info getResultSet(ResultSet rs) throws Exception {
    Info info = new Info();
    info.setPo(rs.getString("po"));
    info.setType(rs.getInt("type"));
    return info;
}

What Does It Do?

Assuming that the testRetrieval() method is a public API defining an operation. I added a higher level performOperation() method to serve as the user of the API. With that in mind, getData() and getResultSet() are really just methods used by testRetrieval and shouldn’t be part of the public API, so I made them private and altered them to just throw all Exceptions’ (which includes checked exceptions) so that testRetrieval() receives all SQLExceptions’ as well as all other Exceptions’. Then testRetrieval() serving as the public API, wraps it’s code-block in a try/catch. The trick is that the catch block calls the bypass method thorwException(), which in turn re-throws the checked exception so that performOperation() can recieve it. Notice how the testRetreival() method does not declare that it throws any exception types.

Then in the performOperation() method that uses the testRetrieval() call, I can have the method called outside a try/catch, in which case any checked exceptions generated by testRetrieval() will simple be passed further up the call stack and eventually to the console or log file (hmm… sounds like a good default don’t you think?).

Optionally I can wrap the testRetrieval() call in a try/catch on the Exception type and then do an instanceof check in the catch block to see if the exception is in fact of the the checked exception type SQLException. It’s important to note that I cannot just catch SQLException because the compiler doesn’t know that we’ve just spoofed it so it’ll still expect testRetrieval() to declare that it throws an SQLException if you try to catch the exception as an SQLException.

The throwException() Bypass Code from thinwire.util.Reflector

public static void throwException(Exception ex) {
    if (ex instanceof RuntimeException)
        throw (RuntimeException) ex;
 
    try {
        synchronized (CheckedExceptionThrower.class) {
            CheckedExceptionThrower.exception = ex;
            CheckedExceptionThrower.class.newInstance();
        }
    } catch (InstantiationException e) {
        throw new RuntimeException(e);
    } catch (IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}
 
private static class CheckedExceptionThrower {
    private static Exception exception;
 
    CheckedExceptionThrower() throws Exception {
        Exception ex = exception;
        exception = null;
        throw ex;
    }
}

How In The Heck Does That Work?

Well, an interestingly little nugget that I stumbled upon in the javadoc for java.lang.Class led to this solution. In the “newInstance()” method documentation it states:

“this method propagates any exception thrown by the nullary ‘zero-argument’ constructor, including a checked exception. Use of this method effectively bypasses the compile-time exception checking that would otherwise be performed by the compiler.”

This somewhat makes sense when you think about it. It means that if the reflection method newInstance() is used to dynamically create an object instance and the constructor for the object throws an exception, that exception whether checked or otherwise will be thrown by the newInstance() method. Thus, calling newInstance() behaves identically to statically constructing the same object in code (i.e. MyObject.class.newInstance() will throw the same exceptions that new MyObject() will). Of course, if you constructed the same class statically in code and the classes constructor threw a checked exception, the compiler would force you to use a try/catch to handle it. But since this is reflection based creation, it bypasses this behavior.

What’s Happening Behind the Scene

Ok, so this probably still doesn’t sit well with you. You’re probably wondering how does newInstance() get away with this? My first guess was that it was making a native call and it is, but in a manner different then you’d expect. The body of newInstance contains the following block of code that makes this all work:

// Run constructor
try {
    return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
    Unsafe.getUnsafe().throwException(e.getTargetException());
    // Not reached
    return null;
}

Isn’t that pretty! The Unsafe class comes from the ’sun.misc’ package. Interestingly enough it offers all sorts of unsafe operations, such as raw memory allocation, but that’s off topic. The bottom line is that the throwException method on the Unsafe class allows checked exceptions to be thrown without the compiler knowing about it. And ultimately that’s what the throwException() method I provided above leverages.

Compatibility Across VM’s

So, you are probably wondering, does this work in other environments or just on Sun’s VM? Truth is that I’m not 100% sure, but if the environment is compliant with the the Class.newInstance() method specification, then this approach should work in that environment. And for compatibility reasons it’s unlikely that Class.newInstance() behaves differently in other environments. As far as I can tell, in the worst case scenario, another environment might wrap up the exceptions caught from the constructor in one of the documented checked exceptions that newInstance() can throw. But in those cases the code above will at least wrap those exceptions in a RuntimeException, thus guaranteeing solid compatibility in all environments. Of course the real solution would be for Sun to wake up and just eliminate or significantly reduce the burden of checked exceptions. But in the meantime, happy hacking!