Exception handling problems in Java, Part I

Author: Kasper B. Graversen, 23/05/08
Keywords: Exception handling, Refactoring, Java
Abstract: Java's type system has a serious flaw. It does not allow refactoring common exception handling code into methods. This article will show the meaty juicy details of the problem.
subscribe to my RSS feed


Bookmark and Share


Exception handling problems in Java, Part I

This article constitutes the part I of a two-part series. Part II is the Exception handling problems in Java, part II

There is something wrong in Java land. Simply put we need better exception throwing behaviour detection in the transitive closure of code blocks in the Java type system. As I will show in this article, the compiler works in mysterious ways! Get ready for some Java type system wrestling!

The core of the problem in laymans terms: Java does not allow you to refactor/extract common exception handling code into a method. Let's have a look at some slightly modified code from my Super CSV project that gave me the inspiration for this article. The code below shows part of the implementation supporting reading CSV files directly into objects. To do that, we need for each column on each line in the file, to invoke a setter method on some object.

There are a few requirements to finding setter methods. Since Java supports method overloading, it is insufficient to just find a setter method on the object with an appropriate name. The type parameter must also be taken into consideration. Further more, since Java also has autoboxing, a class may contain either setAge(int age) or setAge(Integer age) but still respond to the call obj.setAge(2). Hence when looking up a set method, we may require two lookups (one for each of the two possible setAge()). While the folllowing code example may be a bit long, I have chosen a real life example over some contrived made-up bullshit example. You may argue, that the behaviour when trapping a security exception is wrong, I have no problem with that, just mail me a better example.. there are plenty to pick from!

The following example is a lookup method trying to find an appropriate setter method. The autoboxingConverter is a simple map, mapping between autoboxable types to enable the dual lookup as mentioned.
Method inspectClassForSetMethods_old(final Object destinationObject, final Class variableType, final String variableName) {
    final String methodName = "set" + variableName.substring(0, 1).toUpperCase() + variableName.substring(1);

    try {
        return destinationObject.getClass().getMethod(methodName, variableType);
    }
    catch(SecurityException e) {
        e.printStackTrace();
        throw new RuntimeException(String.format("Can't find method '%s(%s)' in class '%s'. "
            + "Is the name correctly spelled in the NameMapping? "
            + "Have you forgot to convert the data so that a wrong set method is called?", methodName, variableType,
            destinationObject.getClass().getName()), e);
    }
    catch(NoSuchMethodException e) {
        // retry again due to autoboxing in java we need to try both cases
        try {
            if( autoboxingConverter.containsKey(variableType) == false ) {
                e.printStackTrace();
                throw new RuntimeException(String.format("Can't find method '%s(%s)' in class '%s'. "
                    + "Is the name correctly spelled in the NameMapping? "
                    + "Have you forgot to convert the data so that a wrong set method is called?", methodName,
                    variableType, destinationObject.getClass().getName()), e);
            }
            return destinationObject.getClass().getMethod(methodName, autoboxingConverter.get(variableType));
        }
        catch(SecurityException e1) {
            e.printStackTrace();
            throw new RuntimeException(String.format("Can't find method '%s(%s)' in class '%s'. "
                + "Is the name correctly spelled in the NameMapping? "
                + "Have you forgot to convert the data so that a wrong set method is called?", methodName,
                variableType, destinationObject.getClass().getName()), e);
        }
        catch(NoSuchMethodException e1) {
            e.printStackTrace();
            throw new RuntimeException(String.format("Can't find method '%s(%s)' in class '%s'. "
                + "Is the name correctly spelled in the NameMapping? "
                + "Have you forgot to convert the data so that a wrong set method is called?", methodName,
                variableType, destinationObject.getClass().getName()), e);
        }
    }
    // return null; // compiler error "unreachable code"
Just quickly glaring at the code, there are a number of worthwhile observations to make
  1. The business logic of the code is drowning in exception handling code. Focus is easily lost.
  2. There is quite a lot of code duplication in the code. Essentially all the catch blocks are identical. This calls for a simple refactoring, Extract method to the rescue! (more on this!)
  3. The last statement in the code is outcommented (return null;). The compiler prevents the existence of that statement by throwing a "unreachable code" error at compile time.
Now here's the punch line (again). Java won't allow you to perform an extract method refactoring!

You would have thought the following refactored code would be legal:
Method inspectClassForSetMethods(final Object destinationObject, final Class variableType, final String variableName) {
    final String methodName = "set" + variableName.substring(0, 1).toUpperCase() + variableName.substring(1);

    try {
        return destinationObject.getClass().getMethod(methodName, variableType);
    }
    catch(SecurityException e) {
        throwException(destinationObject, variableType, methodName, e);
    }
    catch(NoSuchMethodException e) {
        // retry again due to autoboxing in java we need to try both cases
        try {
            if( autoboxingConverter.containsKey(variableType) == false ) {
                throwException(destinationObject, variableType, methodName, e);
            }
            return destinationObject.getClass().getMethod(methodName, autoboxingConverter.get(variableType));
        }
        catch(SecurityException e1) {
            throwException(destinationObject, variableType, methodName, e1);
        }
        catch(NoSuchMethodException e1) {
            throwException(destinationObject, variableType, methodName, e1);
        }
    }
    return null; // Can never be reached.. but the compiler requires it!!
}
/** Confining exception handling code. Must always throw an exception */
private final void throwException(final Object destinationObject, final Class variableType, final String methodName,
    Exception e) throws RuntimeException {
            e.printStackTrace();
            throw new RuntimeException(String.format("Can't find method '%s(%s)' in class '%s'. "
                + "Is the name correctly spelled in the NameMapping? "
                + "Have you forgot to convert the data so that a wrong set method is called?", methodName,
                variableType, destinationObject.getClass().getName()), e);
    }
}
Alas it isn't. This is really a shame, as I hope you would agree with me, it much better communicate its intention of the code, and the code duplication is reduced to a minimum. There is a problem however. The compiler does not detect that the transitive closure (i.e. all the code) of the method throwException() always throws an exception! Hence, it now suddenly refuses to compile the code without the silly and utterly superfluous return null; statement at the end of the code. The error message you get if you leave it out is that the method must return something of type Method.

Our observations from the first code example shows, that the type system is able to analyze all the try-catch blocks and conclude that the return null; in fact never will execute. However, in our second example, the compiler forces upon the programmer to insert that very line of code. Even though the semantics of the code never changed. That return null; never will be executed.

To add confusion to our understanding of the inner workings of the Compiler, try first changing the method throwException() to say throws Exception. Immediately each calling point of the method is highlighted as a compile problem of unhandled exception. Good news! Suddenly the compiler is able to detect that our glamorous throwException() method is capable of throwing exceptions! Then try changing the method inspectClassForSetMethods() to say throws Exception. This will remove the newly arisen compiler errors. However, if then try to removing the return null; statement you'll still get an error message. So it was all smoking mirrors. The checked exception statement only proofed that throwException() could throw an exception not that it always does.

More problems

So returning a null doesn't seem like a big deal. But what if the return type of the method was a simple type, say int. What value would your prefer to be place holder for the unnecessary return statement? It really doesn't matter if it is return 1;, return -1, ... as the statement never is executed, but it sure is bad for readability.

The problem further complicates code generation. I once attempted at cleaning up exception handling in the Business delegate layer of an EJB application I was working on. I felt the pain of first not being able to extract the common functionality into a method, and further when generating the code hand to take into account whether to return a -1 or a null. Trying to use Eclipse IDE's neat "code templates" feature certainly wasn't able to cope with having to make such a distinction.

Solutions

I do not understand why the discussed problem exists. We can only hope to see it disappear in Java 7 or Java 8. The sooner the better! Recently, there has been many blog entries suggesting improvements for the catch-block syntax in Java, allowing multiple exceptions to be caught in the same block. Let's see an example:
    } catch (Exception1 ex) {
       ..
        throw ex;
    } catch (Exception2 ex) {
        ..
        throw ex;
    }
Could be expressed as
    } catch (Exception1 | Exception2 ex) {
        ..
        throw ex;
    }
Unfortunately, this suggestion is orthogonal to the problem that I'm raising. Contemplating on the difference between my suggested solution on what should be possible in Java, and the suggestion of having multiple exception specifiers in the catch block, I must admit I prefer my idea. The main reasons for this is that
  • You can confine exception handling business logic in one part of the application and ensure consistency across the whole application
  • My idea does not require new syntax or learning something new. In fact, it not working is the puzzling part which goes against all rules for good language design and "least surprise for the user".
  • In the multiple catch example, every programmer needs to learn yet another rule. And I have trouble understanding why it the the bit operator OR that separates the exception types, why not use the logical or, it's a much better choice! Then, at least, the syntax and semantics are consistent and syntactically in line with 99.99% of all if statements you probably ever will type.
No doubt though, there should be room for both approaches. Maybe I should file a JSR? What do you think?

This article constitutes the part I of a two-part series. Part II is the Exception handling problems in Java, part II



Comments

If you have any comments to this article, please drop me a mail at firstclassthoughts at gmail dot com please indicate if I can't publish whole or parts of your comment on the site.


If you like this site consider subscribing to my RSS feed or how about subscribing by Email.


Help spread the word

Share this post on your favorite social bookmarking sites:
If you enjoyed this article, found it thought provoking, educative or otherwise good, please link to this page from your page or social bookmarking page. If you have any texts you think are worth publishing on First Class Thoughts, don't hesitate to send me a mail! Quality always welcome.


Bookmark and Share


The most recent contributions
28/07/09 Magic in mathematics II Fun with the number cyclic numbers, and specifically with 142857 as it is the smallest of such numbers.
13/07/09 My top 8 time-saving Firefox shortcuts This article presents my favorite top 8 time-saving shortcuts in Firefox 3.0 and Firefox 3.5. Get to know these and you'll be saving a lot of time. They have been ordered by "the element of most surprise"
20/05/09 Board Game Jungle speed / Arriba Review of the cool game "Jungle Speed" aka. "Arriba".
16/05/09 Danish Twin words "Twin words" are words that not only have multiple meanings, they must be composed next to each other in meaningful sentences. This article explores the concept of twin words.
Nothing of interest? Try browsing the entire article archive...