Throwing undeclared checked exceptions

Sometimes checked exceptions can be a problem. I tried to implement a common logic to retry failing network operations and it resulted into a kind of command pattern on which, as usual, the execute() method throws java.lang.Exception. That complicated the caller code that 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

 1import java.lang.reflect.Field;
 2import sun.misc.Unsafe;
 3
 4public class UnsafeSample {
 5    public void methodWithNoDeclaredExceptions( ) {
 6        Unsafe unsafe = getUnsafe();
 7        unsafe.throwException( new Exception( "this should be checked" ) );
 8    }
 9
10    private Unsafe getUnsafe() {
11        try {
12            Field field = Unsafe.class.getDeclaredField("theUnsafe");
13            field.setAccessible(true);
14            return (Unsafe) field.get(null);
15        } catch(Exception e) {
16            throw new RuntimeException(e);
17        }
18    }
19
20    public static void main( String[] args ) {
21        new UnsafeSample().methodWithNoDeclaredExceptions();
22    }
23}

This makes use of internal Sun JRE libraries implementation classes. 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)

 1public class ThreadStopExample {
 2
 3    @SuppressWarnings("deprecation")
 4    public void methodWithNoDeclaredExceptions( ) {
 5        Thread.currentThread().stop(new Exception( "this should be checked" ));
 6    }
 7
 8    public static void main( String[] args ) {
 9        new ThreadStopExample().methodWithNoDeclaredExceptions();
10    }
11}

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()

 1public final class Class<T>  ... {
 2    public T newInstance()
 3        throws InstantiationException, IllegalAccessException
 4}
 5
 6public final class Constructor<T> ... {
 7    public T newInstance(Object ... initargs)
 8    throws InstantiationException, IllegalAccessException,
 9               IllegalArgumentException, InvocationTargetException
10}

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.

 1public class Exceptions {
 2    private static Throwable throwable;
 3
 4    private Exceptions() throws Throwable {
 5        throw throwable;
 6    }
 7
 8    public static synchronized void spit(Throwable throwable) {
 9        Exceptions.throwable = throwable;
10        try {
11            Exceptions.class.newInstance();
12        } catch(InstantiationException e) {
13        } catch(IllegalAccessException e) {
14        } finally {
15            Exceptions.throwable = null;
16        }
17    }
18}
19
20public class TestExceptionSpit {
21    public static void main(String[] args) {
22        Exceptions.spit(new Exception( "this should be checked" ));
23    }
24}

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

 1import java.rmi.RemoteException;
 2
 3public class Bridge {
 4    public void methodWithNoDeclaredExceptions( ) {
 5        sun.corba.Bridge.get().throwException(new RemoteException("bang!"));
 6    }
 7
 8    public static void main( String[] args ) {
 9        new Bridge().methodWithNoDeclaredExceptions();
10    }
11}

This is more or less the same as using the 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...

 1import java.rmi.RemoteException;
 2
 3class Thrower {
 4    public static void spit(final Throwable exception) {
 5        class EvilThrower<T extends Throwable> {
 6            @SuppressWarnings("unchecked")
 7            private void sneakyThrow(Throwable exception) throws T {
 8                throw (T) exception;
 9            }
10        }
11        new EvilThrower<RuntimeException>().sneakyThrow(exception);
12    }
13}
14
15public class ThrowerSample {
16    public static void main( String[] args ) {
17        Thrower.spit(new RemoteException("go unchecked!"));
18    }
19}

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 that. 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 instead 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.


2 Responses to “Throwing undeclared checked exceptions”  

  1. 1 kodeninja

    Hmmm.. couple of these would be a nice addition to my kitty of Java hacks/tricks :)

    Gr8 post Luigi!

  2. 2 Luigi

    You’re welcome!

    If you put your tricks online, send me the link ;)

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>


Current ye@r *


Calendar

November 2008
M T W T F S S
« Oct   Dec »
 12
3456789
10111213141516
17181920212223
24252627282930

Follow me

twitter flickr LinkedIn feed

Subscribe by email

Enter your email address:

Archives


Categories

Tag Cloud


Listening