Vote up, vote down. It doesn't matter which - just vote! Login and vote now.
By jj83777
via tutorials.jenkov.com
Published: Feb 14 2008 / 09:41
Exception enrichment is an exception handling technique which solves the problems of the long stack traces of exception wrapping. Rather than wrap caught exceptions, the original exception is rethrown with some extra context information added. This technique also provides a method to achieve truly unique error codes in an application, making it possible to distinguish exceptions thrown from the same piece of code, but called from different contexts.
Comments
otupman replied ago:
I like this idea, but has anyone got a) any better ideas and/or b) problems that might result in this idea?
I'm currently dealing with an app that throws exceptions deep, deep, deeeeeep within code and the stack traces end up being incredibly long. I like the idea of adding extra to an exception. Of course the calling code still has the option of wrapping the exception, if it so chooses so it doesn't constraint developers.
scruffles replied ago:
The entire premise of exception enrichment is based on the output of printStackTrace(). Why not just implement your own static method printStackTrace(Throwable t) that prints the stack trace as you want to see it? In the examples he gave, he just wanted to see the messages for each embedded exception and the stack trace for the lowest level exception. This is exactly how we printed stack traces at my last job. It worked great, and didn't require a lot of work. We used a custom library for logging, but you could easily create your own log4j Layout to format exceptions as you want. Creating an exception framework to get prettier stack traces seems like overkill.
,
Jakob Jenkov replied ago:
It is not just the stack trace that gets prettier, though its a big part of it. It is also a simple way of creating completely unique error codes in an application, which makes it possible to determine not only the origin of the exception, but also the context on the way up the call stack. An SQLException can be thrown in many different places without it being the same error. You may even want to know if the caller of the DAO was the web interface, or a web service. Anyone who has worked on applications that need to log unique error codes for the sake of surveillance could use that. This is what you get with the simple unique error code scheme proposed in this text too.
Of course you could do this too with exception wrapping, but you would have to implement the error context and error code in all wrapping exceptions up the hierarchy. This could be many different exception classes throughout the application. With an EnrichableException you only need to implement it once. And it is not really a "framework". All you really do is to add a bit of extra methods / members to the base exception of your application, and you are off the ground.
Having said that, exception enrichment probably best suits applications that use unchecked exceptions and which primarily just let them bobble up and log them. This is often the case in web applications anyways.
scruffles replied ago:
I had assumed the list of goals stated at the top of the article were the focus of the framework, and the error codes were a nice side effect (since they weren't mentioned in the intro).
I can imagine a situation where keeping track of the context of an exception might be useful, although, if you can't recover from the exception based on that context, then it's just another diagnosis tool that could be applied in logging.
The reason I use the term 'Framework' is because it would alter the way you code across the application. I don't have a 'base exception' where all other exceptions inherit from. I use the exception most appropriate for the situation. If I think a user should be aware of the situation, and can take corrective measures, I use a checked exception; otherwise I use a runtime exception. In either case, I use specific exceptions and take advantage of types. I use the term 'framework' because using a single exception hierarchy across the application is an application-wide style change that wouldn't be isolated to an API or subset of the program.
Jakob Jenkov replied ago:
clarification: Even if an SQLException is thrown from within the same DAO, because of the same logical error inside the DAO, the context of the error may vary depending on what component called the DAO. You might want the error code to reflect that.
Jakob Jenkov replied ago:
One last comment... I don't like exception wrapping in general. It has a clumsy feel to it, and the wrapping exceptions don't really add any value. The stack traces of the wrapping exceptions is of no use. Only the extra messages are. And they can be added just as easily to the original exception.
Having said that, the SQLException mentioned in the comments above would of course have to be wrapped once, in an EnrichableException or whatever you choose to call your own implementation.
scruffles replied ago:
The value exception wrapping adds is changing the exception type. A DAO might throw a DataSource exception rather than a SQLException. The fact that the DAO uses JDBC rather than file access or Hibernate is of no value to the DAO user. There are a lot of good examples in network access, where low level exceptions are good for recovery, but application developers may want to abstract exceptions in ways that couldn't be anticipated when the API's designer wrote the exception hierarchy.
warpedjavaguy replied ago:
What happens if you directly throw EnrichableException in ExceptionTest.level4() instead of IllegalArgumentException? The exception is swallowed! I know that you would not typically do this but it is a possibility and these things do inadvertently happen in team environments. One solution could be to rethrow the EnrichableException in the handler after adding the error info to it.
I do like it though :)
Jakob Jenkov replied ago:
@warpedjavaguy:
Perhaps the example isn't perfect. But it's just an example, right? :-) It's the idea of not wrapping but just adding information to the original exception that is the point of the text.
@scruffles:
1) Exception wrapping is primarily seen in Java, and mostly because Java has checked exceptions. I suspect exception wrapping is used a lot less in .NET which only has unchecked exceptions. In fact Anders Hejlsberg and Gosling were interviewed about this topic a couple of years ago on artima.com.
2) Enrichment does not prevent wrapping, nor recovery. Use enrichment when it makes sense. Don't use it in areas of the application where it doesn't make sense. It typically makes sense in the higher level layers of an application.
3) if the DAO throws an EnrichableException (or an appropriate subclass hereof) you will have about the same result. The user of the DAO doesn't see the SQLException, because it is wrapped in the EnrichableException. But even if the user did get the SQLException and it was enrichable, would the user care? Is an SQLException any *worse* than a more general DAOException?
An often used argument is that wrapping or translating exceptions encapsulate lower level API details from higher levels of the application. But for what purpose? What is really gained in this translation? The major reason it is nice to abstract lower level exceptions away from higher level layers is to avoid forcing the higher level layers to catch a gazillion different lower level checked exceptions. With enrichable exceptions the higher levels don't have to.
What would happen if the whole application throws the same application from top to bottom? If you don't have an exception hierarchy? As long as you still have the unique error codes you can still respond individually to each exception. In fact you are probably getting more detail from an EnrichableException that also contains a dynanic unique error code, than a general DAOException which only in words tell what went wrong.
I know a common response is that the DAO would throw appropriate subclasses of DAOException, like ErrorOpeningConnectionException etc. But these special subclasses add no more value to the catcher than a unique error code does. In addition, in my experience big applications start out with the best of intensions on creating a finegrained exception hierarchy to make the application capable of dealing individually with each exception. Then, after the third (or fifth or tenth whatever) subclass in the hierarchy is defined and thrown, and the application still just lets it bobble up to be logged centrally, the developers stop adding new special subclasses and use the more general ones, like DAOException. So you end up with a crippled exception hierarchy. The subclasses don't often add extra value. They are just extra trouble.
Using exception enrichment the developers would only have to worry about a handful or two of local error codes inside a component. The way the dynamic error codes are put together in the EnricableException text, they actually form a hierarchy too, but with a lot less effort than defining a fine grained exception hierarchy. As the application evolve the hierarchy evolves with it too. And, the error codes are always right there, ready to use for logging.
Voters For This Link (18)
Voters Against This Link (2)