I have a method like this:
public void getSomething(){
...
}
I want to throw an Exception
inside getSomething()
. The compiler will not allow me to do that because my method doesn't allow Exception
to be thrown in there. But I need to throw a subclass of Exception
for my testing (I can't throw Unchecked Exception
). This is clearly a hack but I need it for my testing. I tried EasyMock but it doesn't allow me to do that either. Any ideas how to do that?
Thanks, Sean Nguyen
Method 1:
This post by Alexey Ragozin describes how to use a generics trick to throw an undeclared checked exception. From that post:
public class AnyThrow {
public static void throwUnchecked(Throwable e) {
AnyThrow.<RuntimeException>throwAny(e);
}
@SuppressWarnings("unchecked")
private static <E extends Throwable> void throwAny(Throwable e) throws E {
throw (E)e;
}
}
The trick relies on throwUnchecked
"lying" to the compiler that the type E
is RuntimeException
with its call to throwAny
. Since throwAny
is declared as throws E
, the compiler thinks that particular call can just throw RuntimeException
. Of course, the trick is made possible by throwAny
arbitrarily declaring E
and blindly casting to it, allowing the caller to decide what its argument is cast to - terrible design when coding sanely. At runtime, E
is erased and has no meaning.
As you noted, doing such a thing is a huge hack and you should document its use very well.
Method 2:
You can also use sun.misc.Unsafe
to this end. First you must implement a method that uses reflection to return that class's instance:
private static Unsafe getUnsafe() {
try {
Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
return (Unsafe)theUnsafeField.get(null);
}
catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
This is necessary as calling Unsafe.getUnsafe()
will typically throw a SecurityException
. Once you have the instance of Unsafe
you can put its terrifying capabilities to use:
Unsafe unsafe = getUnsafe();
unsafe.throwException(new Exception());
Credit goes to this answer on the post https://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe. I thought I'd mention this for completeness but it's probably better just to use the trick above instead of allowing Unsafe
into your code.
Method 3:
In the comments of the linked answer about using Unsafe
, @bestsss points out a much simpler trick using the deprecated method Thread.stop(Throwable)
:
Thread.currentThread().stop(new Exception());
In this case you would use @SuppressWarnings("deprecation")
and once again document very fiercely. Again, I prefer the first trick for its (relative) cleanliness.