This is my attempt to make a ChuckNorrisException
in Java, an exception that cannot be caught. The implementation is interesting, because it actually throws an exception, and it may cause a true confusion if you see it for the first time.
Okay, what would you expect to see on the screen after running the following piece of code?
Of course, the obvious answer is: I’ve caught ChuckNorrisException. Unfortunately, not this time. The actual result is presented below, and believe me, you do not want to see something like this in the production:
Yes, this is an ordinary JDK8, and it is real. Read the next section to see how this is possible.
ChuckNorris is uncatchable…
To make an uncatchable exception in Java, we need two things: another classloader and a bytecode manipulation library. I chose javassist. The classloader is pretty simple and has no hidden tricks. I’ll explain later why we need it:
The actual magic happens in the constructor of ChuckNorrisException
:
The key to understand this code is the knowledge how JVM identifies classes. The most obvious answer is using fully qualified class name, but it is only partially correct, as it refers only to what we see in the source code. Actually, JVM uses a pair of class name, and… the classloader - there can be two distinct classes with identical names, provided they have been loaded by two different class loaders. While working with regular applications, we do not have to be aware of that, but this feature is quite important for application servers, because it allows isolating the applications running in the same JVM at the binary level.
The constructor of our exception is special, because it actually never finishes. It contains the code to make a copy of its own class, and attaches it to the new classloader (1). Since then, we have two distinct (from the JVM perspective) norris.ChuckNorrisException
classes in our memory. With reflection, we obtain a separate private constructor to avoid falling into an infinite loop, create the new exception instance (2), and finally throw it to the user, instead of the instance the constructor is working on (4). The catch
clause matches the exceptions by the classloader of the current thread, but our actual exception uses a different classloader, so it cannot be caught.
There is only one thing left: the stacktrace. The inspection of the message about uncaught exception would reveal us that something strange is going on in the constructor:
Fortunately (for us), the exception class is not immutable, and has a publicly available setStacktrace()
method. So all we have to do is to copy the stacktrace from one exception instance to another (3). Now the impression is perfect. Without an inspection of the exception code, the thrown exception is indistinguishable from the one that the user would expect… almost…
… except one case
The only place, where the illusion crashes, is the following piece of code:
The Throwable
class is preloaded by the system loader, and the actual classloader implementation provided to the regular programmers prohibits loading classes from java. package. This logic is hardcoded in the final method, so there is no way to change it. While we replaced the class of ChuckNorrisException
, it still extends the regular Exception
and Throwable
classes whose classloaders do match the one of the current threads (the classloaders form a tree, and child classloader A is always considered to match its parent classloader as well). As a result, more general clauses are able to catch our exception.
There is one more trick we can do to escape. Think about what a typical programmer does after catching the exception. He calls such methods, as getMessage()
, getStackTrace()
, maybe there are still guys who use printStackTrace()
. We can overwrite these methods and tune them to behave correctly only in the uncaught exception handler:
Just note that getStackTrace()
is used in the constructor. To avoid accidental roundhouse kicking ourselves, I added a flag variable illusion
which is set to false in the public constructor, and true in the private one.
Is this implementation correct according to the story about Chuck Norris and Java? While it is not perfect, this imperfection can be easily explained. Look, we catch an unknown object, we do not know what is inside. And if we try to cast it back to ChuckNorrisException
, or call getMessage()
:
Blah! Chuck Norris jumps out of the object and roundhouse kicks your application:
For me, the confusion level is satisfactory enough to call it the working ChuckNorrisException
implementation for Java, and probably the best one we can have. But please, try not to use this in the production code :).
The sources can be found on Github.