views:

663

answers:

4

Is there a way to annotate a method so all exceptions thrown are converted to runtime exception automagically?

@MagicAnnotation
// no throws clause!
void foo()
{
  throw new Exception("bar")'
}
A: 

You can do this with AspectJ. You declare a joinpoint (in this case invocation of the method foo) and 'soften' the exception.

Edit To elaborate a bit on this:

Say you have the following class Bar:

public class Bar {

    public void foo() throws Exception {
    }
}

...and you have a test like this:

import junit.framework.TestCase;

public class BarTest extends TestCase {

    public void testTestFoo() {
     new Bar().foo();
    }
}

Then obviously the test is not going to compile. It will give an error:

Unhandled exception type Exception  BarTest.java(line 6)

Now to overcome this with AspectJ, you write a very simple aspect:

public aspect SoftenExceptionsInTestCode {

    pointcut inTestCode() : execution(void *Test.test*());

    declare soft : Exception : inTestCode();
}

The aspect basically says that any code from within a Test (i.e.: a method that starts with "test" in a class that ends in "Test" and returns 'void') that throws an exception should be accepted by the AspectJ compiler. If an exception occurs, it will be wrapped and thrown as a RuntimeException by the AspectJ compiler.

Indeed, if you run this test as part of an AspectJ project from within Eclipse (with AJDT installed) then the test will succeed, whereas without the aspect it won't even compile.

Maarten Winkels
I think this is a fair answer (although I don't know anything about AOP besides the concepts). Wonder why it was downvoted?
kd304
Sample code would be very nice - there are many new concepts when looking on AOP which is hard to get right.
Thorbjørn Ravn Andersen
+1  A: 

I think it is possible with bytecode re-engineering, customized compiler or perhaps aspect oriented programming1. In the contrary to Java, C# has only unchecked exceptions2.

May I ask why you want to suppress the checked exceptions?

1 according to Maarten Winkels this is possible.
2 and they are thinking about introducing checked ones, according to some Channel 9 videos.

Edit: For the question: It is possible in the sense that you can annotate your methods to flag them to be a candidate for checked exception suppression. Then you use some compile time or runtime trick to apply the actual suppression / wrapping.

However, as I don't see the environment around your case, wrapping an exception in these ways might confuse the clients of that method - they might not be prepared to deal with a RuntimeException. For example: the method throws an IOException and your clients catches it as FileNotFoundException to display an error dialog. However if you wrap your exception into a RuntimeException, the error dialog gets never shown and probably it kills the caller thread too. (IMHO).

kd304
Test code, I don't really care about which exceptions at that point.Also, my take in the checked-exceptions-yes-or-no is a rather solid No (but will conform to standard and not have all my exceptions extend RuntimeException for production code).
ripper234
Thank you. I think having the option for use checked exception is good - it allows you to 'guide' your clients. However, I sometimes feel it too, in some particular cases, that an exception should have been the other type. Still, on conceptional level, I think my answer still stands.
kd304
+1  A: 

The way I do it without annotations is to have a method wrapper which calls the desired method with exceptions and all inside a

try {
  methodThrowingLotsOfExceptions();
} catch (RuntimeException e) {
   // avoid wrapping if not needed
   throw e;
} catch (Exception e)
  throw new RuntimeException("wrapped thrown exception from method()", e);
}

This avoids the try-catch inside the troublesome method allowing for better readability, without putting code "away" in an annotation .

--

Edit: Personally I believe that checked exceptions have their merit, in saying "You - the programmer - CAN handle this, please consider what should be done". It really helps in considering border cases when doing the original design, which usually means that the design is better fittet for actually handeling border cases. (Instead of some poor maintainer having to wring the inside out, to get the code to handle a customer problem. "Oh, you don't want the application to crash if the network drive is unavailable...")

In your particular case, you actually have considered this (and decided you don't want to think anymore about it). You may also want to subclass your exceptions saying what caused the problem, this will alllow you to handle this better upstream. Here I think that instead of just throwing a RuntimeException("Network drive unavailable") you may want to create a NetworkDriveUnavailableException() instead so your CODE can be more readable and robust if you catch this at a higher level.

Thorbjørn Ravn Andersen
Just one comment. It could be useful to have the runtime exception use the message from the wrapped exception in its constructor, so when you check the logs for error, the actual exception message becomes visible at the top and not just in one of the caused by... part of the stacktrace.
kd304
A: 

You can do this in any case via use of the fact that Class.newInstance does not wrap an Exception thrown by the no-arg constructor in an InvocationTargetException; rather it throws it silently:

class ExUtil {
  public static void throwSilent(Exception e) { //NOTICE NO THROWS CLAUSE
      tl.set(e);
      SilentThrower.class.newInstance(); //throws silently
  }

  private static ThreadLocal<Exception> tl = new ThreadLocal<Exception>();
  private static class SilentThrower {
      SilentThrower() throws Exception {
          Exception e = tl.get();
          tl.remove();
          throw e;
      }
  }
}

Then you can use this utility anywhere:

ExUtil.throwSilent(new Exception());
//or
try {
  ioMethod();
} catch (IOException e) { ExUtil.throwSilent(e); }

By the way, this is a really bad idea :-)

oxbow_lakes