After having worked with various legacy codebases one discovers certain recurring traits and patterns. The topic of today is the Custom Exception Hierarchy encountered in Java legacy code. This phenomenon is rather Java-specific because of that language’s checked exceptions.
So what is a Custom Exception Hierarchy? It’s an exception hierarchy, with some strangely named exception at its root, present throughout the entire codebase and used everywhere. The author(s) of such hierarchy obviously felt that exceptions like
IllegalArgumentException, or the like weren’t sufficient for the sophisticated needs of their application, so they came up with a better suited hierarchy of checked exceptions.
For this blog post, I’ve made a detailed study of three such hierarchies. I’m trying to understand how they came about. Let’s have a look.
I don’t have access to this source code any more, but I know that there was a checked
RException at the bottom of the hierarchy and that it wasn’t too deep. This exception wasn’t used too extensively. Now, the explanation to this exception is quite interesting and almost logical.
This particular codebase didn’t only have an
RException. It had 50-100 classes starting with a capital R. For example
RTextField, and so on. Believe it or not, there was a good reason for this. When this code was written, Java’s focus handling was completely broken (around version 1.1-1.4). Therefore a separate class hierarchy was used to “fix” this; all components in this hierarchy had their custom focus handling. I don’t remember whether this was the best solution to the focus handling problem, but it certainly was one.
As for the
RException… I’m not sure, but I’m speculating that it either came about because the author of the parallel hierarchy felt that 50-100 custom classes deserved their own exception (by analogy) or because it contained some functionality related to focus handling. Brrr.
And by the way… Why “R”? It was the first letter of the company’s name.
The CompanyName-SystemName hierarchy
This hierarchy doesn’t have an equally interesting tale as the R-hierarchy. As always, the name of the company and system are not revealed, but again we have two exceptions inheriting from
java.lang.Exception sitting on top of each other.
The exception at the root of the hierarchy actually contained a bunch of methods related to resolving different exception “message keys” to strings in a message bundle, which was specific to the exception. The author’s intent was obviously something like this:
throw new CompanyNameException(“error.nosuchcustomer”, customerId, exception);
Again… this would almost make sense, but not all application exceptions should result in a user-friendly message and you don’t want to force people into creating strings in a message bundle only because they want to throw an exception in a consistent manner (yes, this exception was circumvented and people threw other exceptions because of the inconvenience).
To make matters more complicated there was a second exception inheriting from the CompanyNameException. It was named after the system, and didn’t serve any purpose at all. The remaining exceptions inherited from it, and all of them had to pass various “message keys” to the CompanyNameException. This hierarchy was so abandoned when Spring was introduced. Happy ending.
The ApplicationException hierarchy
The third tale is about the
ApplicationException hierarchy. What’s interesting about this hierarchy is the fact that it immediately clashes with both the EJB concept of application exception and an annotation,
javax.ejb.ApplicationException. The purpose of this exception is clearly defined in its Javadoc:
* Exception class for general purpose application exceptions. * This is useful in the EJB tier when it is inconvenient to pass e.g. a * SQLException to the web tier and EJBException is to be avoided because it is * a RuntimeException. */ public class ApplicationException extends Exception
I’m not sure whether the author was aware of how exceptions affect JEE’s transaction handling, in particular moving from a runtime exception to a checked exception, but at least the intent is clear. What’s also interesting about this exception is that it tries to do the exact opposite of what modern frameworks do.
The next exception in this hierarchy was an
OrderException, which encapsulated everything that had anything to do with the system’s handling of orders. From JMS failures to invalid arguments.
And the conclusion is…
Strange exceptions have been created in legacy code for reasons that may seemed valid at some point in time. This applies to many constructs in such code. One of the driving forces could be legacy developers’ intrinsic love for inheritance (do I smell another code archeology blog post here?).
I guess that the conclusion is that customer exception hierarchies will be around for another half a decade, because throwing them away in a single sweep might be too much of a refactoring, especially if it affects the transaction semantics. On the other hand, new code doesn’t need to respect them, as long as it behaves correctly. Here and there, the descendents of
ApplicationException may be changed into exceptions from
java.lang or new ones that make more sense. Eventually they will die childless (wow, that came out dramatic 🙂 ).