Throwing Undeclared Checked Exceptions
Sometimes checked exceptions can be a problem. For instance, recently I tried to implement some common logic to retry failing network operations and it resulted in a kind of command pattern on which, as usual, the execute() method throws java.lang.Exception. That complicated the caller code which has to catch and handle java.lang.Exception instead of the more specific exceptions...
I knew that checked exceptions are enforced by the compiler, while in the virtual machine there is nothing preventing a checked exception to be thrown by a method not declaring it, so I started to check on internet how to implement this.
I found two posts on Anders Noras's blog (#1 #2) on how to perform this magic.
Method #1: the sun.misc.Unsafe class
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class UnsafeSample {
public void methodWithNoDeclaredExceptions( ) {
Unsafe unsafe = getUnsafe();
unsafe.throwException( new Exception( "this should be checked" ) );
}
private Unsafe getUnsafe() {
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
public static void main( String[] args ) {
new UnsafeSample().methodWithNoDeclaredExceptions();
}
}
This makes use of internal Sun JRE libraries implementation classes. It could not work if you use a non Sun VM. And in fact it doesn't if you use GCJ (The GNU compiler for Java).
The getUnsafe() method exposed above does some tricks to access a private field in the Unsafe class, because Unsafe.getUnsafe() can only be called by classes loaded by the bootstrap ClassLoader.
See also the article Avoiding Checked Exceptions by Don Schwarz.
Method #2: the Thread.stop(Exception)
public class ThreadStopExample {
@SuppressWarnings("deprecation")
public void methodWithNoDeclaredExceptions( ) {
Thread.currentThread().stop(new Exception( "this should be checked" ));
}
public static void main( String[] args ) {
new ThreadStopExample().methodWithNoDeclaredExceptions();
}
}
This uses a deprecated method, but works. No portability issue, until the Java specification guys decide to remove the method.
It could have some side effects on the current thread as we are calling stop(). I'm not sure.
Method #3: using Class.newInstance()
Look at the signature of java.lang.Class.newInstance() and compare it to Constructor.newInstance()
public final class Class ... {
public T newInstance()
throws InstantiationException, IllegalAccessException
}
public final class Constructor ... {
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
}
You see it? no InvocationTargetException!
If you call SomeObject.class.newInstance() and the constructor throws an exception, the exception doesn't get wrapped into the InvocationTargetException (that is a checked exception).
So you can write an utility class like this, to throw checked exceptions without needing to declare them on the method signature.
public class Exceptions {
private static Throwable throwable;
private Exceptions() throws Throwable {
throw throwable;
}
public static synchronized void spit(Throwable throwable) {
Exceptions.throwable = throwable;
try {
Exceptions.class.newInstance();
} catch(InstantiationException e) {
} catch(IllegalAccessException e) {
} finally {
Exceptions.throwable = null;
}
}
}
public class TestExceptionSpit {
public static void main(String[] args) {
Exceptions.spit(new Exception( "this should be checked" ));
}
}
Internally the Class.newInstance() uses the sun.misc.Unsafe class, but in this case this technique is fully portable because you are not using any deprecated or internal method. In fact it works also with GCJ JVM.
I tried to remove the synchronization stuff and the static field using an inner class, but it seems that the compiler does some strange trick translating the empty constructor in something else preventing Class.newInstace() to be used on that inner class.
The behavior of the Class.newInstance() is also documented:
"Note that this method propagates any exception thrown by the nullary
constructor, including a checked exception. Use of this method
effectively bypasses the compile-time exception checking that would
otherwise be performed by the compiler."
So your code is fully safe and compliant to the rules :)
Method #4: the sun.corba.Bridge
import java.rmi.RemoteException;
public class Bridge {
public void methodWithNoDeclaredExceptions( ) {
sun.corba.Bridge.get().throwException(new RemoteException("bang!"));
}
public static void main( String[] args ) {
new Bridge().methodWithNoDeclaredExceptions();
}
}
This is more or less the same as using the Unsafe.class. The difference is that in this case you don't need to do the reflection stuff to access the private field "theUnsafe", because the Bridge class is doing that for you. Still using an internal JRE class with same portability issues.
Method #5: Generics
The following example takes advantage of the fact that the compiler does not type check generics...
import java.rmi.RemoteException;
class Thrower {
public static void spit(final Throwable exception) {
class EvilThrower<T extends Throwable> {
@SuppressWarnings("unchecked")
private void sneakyThrow(Throwable exception) throws T {
throw (T) exception;
}
}
new EvilThrower().sneakyThrow(exception);
}
}
public class ThrowerSample {
public static void main( String[] args ) {
Thrower.spit(new RemoteException("go unchecked!"));
}
}
Credits to "Harald" that posted a comment on Johannes Brodwall's blog.
I personally think this last one is the best solution: it uses a feature of the compiler against itself.
Conclusions
I think that having checked exception in Java is better than not having it. I already expressed why I am in favor of checked exceptions here. It's a design decision, you can choose to make your exceptions checked or unchecked, if you want to force your client to handle them or not; you can't do that on .NET, where checked exceptions simply do not exist.
Sometimes you have (or you have to write) methods throwing java.lang.Exception, and you get into the trap. So you may like to know that there is a dirty escape, and you can decide to use it or not... we saw that Sun is throwing undeclared checked exceptions in Class.newInstace(), ask yourself: if this is good for the JRE code, could it be good also for yours?
Usually you can wrap checked exception into RuntimeExceptions but this doesn't simplify the client code, because the caller in case of needing has to catch the RuntimeException, unwrap the cause and deal with it. Maybe a new Java keyword to throw checked exception without requiring the caller to handle them could help: I recommend reading post on Ricky Clarkson's about checked exceptions.
Finally I come to the decision to not use those tricks in my object doing the retry logic, and keep the messy catch logic on the caller code. In case of needing I will evaluate to use a Dynamic Proxy doing the retry logic and keeping its behavior transparent to the client.
To those who wants unchecked exceptions in Java... well, there is the way to have it: the example with Generics is a clean way to have it. Use it if you want, at your own risk.
Personally I would choose to use libraries with checked exceptions...
Other related articles
Friday Free Stuff by Chris Nokleberg, uses bytecode manipulation.
Don't Try This at Home by Bob Lee, exposes some methods also covered above.
From: http://en.newinstance.it/2008/11/17/throwing-undeclared-checked-exceptions/
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Alessandro Santini replied on Wed, 2010/09/15 - 2:38am
I personally would have come to a slightly (but just slightly) different conclusion: I would have kept the exception catch/retry logic in the command bean. This way, you could implement different Commands aiming at the same Target but with different logic (with or without retry, for instance). Being a Command, all these implementations would be sharing the same interface.
Why the execute() method must necessarily return Exception? The Command bean could again be an excellent substitute for exception conversion (from the target context to the client context) e.g. converting an SoapException into something more like InvalidCommandException.
If I did not understand the context of your problem, my apologies :)
Ciao,
Alessandro
Fabrizio Giudici replied on Wed, 2010/09/15 - 3:33am
Luigi Viggiano replied on Wed, 2010/09/15 - 8:59am
Fabrizio (ciao!)
I knew Lombok, but I didn't knew this feature... The problem with those exception is that the compiler will refuse to catch those exception because "exception XyzCheckedException is never thrown in body of corresponding try statement"
It's important to not abuse those techniques then... actually it's very hard to do a good usage of it :-)
I am not recommending to use those, but still it's good to know about it.
Luigi Viggiano replied on Wed, 2010/09/15 - 9:33am
in response to:
Alessandro Santini
Alessandro,
I didn't explain in detail how my little Retry logic had to work. Basically it was something like:
retry(times(3), delay(5000, ms), new Logic() { public void run() throws Throwable { ... } }) .when(RemoteException.class, new RemoteExceptionHandler()) .when(SocketException.class, retry()) .when(FooBarException.class, ignore()) .when(NoRouteToHostException.class, abort()) .execute();the execute() method shall still throw one of the exception that caused the retry or the abort, so the application can still receive the signal of what went wrong and why. I mean: I retry three times when there is a SocketException but the 4th time I let the exception to flow out. For this reason, the execute() method, that has to be independen from the internal logic, must still throw out any possible exception that the Logic object may throw. I don't know if I clarified.
At the end I had to put the above code in a try catch.
BTW, I didn't go in detail of the scope of the retry logic above, as it is, in my opinion, less interesting than how the compiler can be cheated to do something "impossible" :-)
Fabrizio Giudici replied on Wed, 2010/09/15 - 1:04pm
in response to:
Luigi Viggiano
Alessandro Santini replied on Wed, 2010/09/15 - 3:01pm
in response to:
Fabrizio Giudici
Liam Knox replied on Wed, 2010/09/15 - 9:29pm
Luigi Viggiano replied on Wed, 2010/09/15 - 10:13pm
in response to:
Liam Knox
Liam Knox replied on Wed, 2010/09/15 - 10:45pm
in response to:
Luigi Viggiano
I see that the Generics implementation get caught by the compiler in Java 5/6
<code>
C:\tmp>javac -cp . thrower/Thrower.java
thrower\Thrower.java:11: unreported exception java.lang.Throwable; must be caugh t or declared to be thrown new EvilThrower().sneakyThrow(exception); ^ 1 error
</code>Liam Knox replied on Thu, 2010/09/16 - 3:09am
in response to:
Luigi Viggiano
finalcaveats etc) behaviour as Retryable with out needing the SAM type. Horses for courses reallyWe actually used a full annotation based AOP approach in certain areas
Bozhidar Bozhanov replied on Fri, 2010/09/17 - 1:51am
And what is the problem of
throw new RuntimeException(originalException);
Liam Knox replied on Fri, 2010/09/17 - 10:43pm
in response to:
Bozhidar Bozhanov
My 2 cents. Checked exception are a complete pile of crap, the whole heirachy is a mess, there use cases in the core APIs are wrong ( see IOException, FormatException, SQLException etc ) and in the end for what tangilble gain? None.
Designers miss the point totally, having 2 variants of an idiom does not increase the complexity by a factor of 2. It increases it anywhere between 2 an infinity. In the world of exceptions it is more like the latter.