0

Consider this code:

@Test(expected = NullPointerException.class)
public void testSaveEmptyApplication() {
    try {
        Application application = new Application();
        Application result = applicationService.save(application);
    } catch (Exception e) {
        if(e instanceof UncheckedServiceException) {
            throw e.getCause(); // java.lang.Throwable, compiler error
        }
    }
}

How to re-throw a Throwable?

Sri
  • 437
  • 1
  • 4
  • 13
Fireburn
  • 981
  • 6
  • 20
  • 2
    did you try `testSaveEmptyApplication() throws Throwable`? – Gautham M Mar 24 '21 at 05:28
  • Please paste the error message from the compiler into your question so we can all be sure what we are talking about. – Ole V.V. Mar 24 '21 at 05:29
  • Does this answer your question? [Why is it legal to re-throw a Throwable in certain cases, without declaring it?](https://stackoverflow.com/questions/23581611/why-is-it-legal-to-re-throw-a-throwable-in-certain-cases-without-declaring-it) – Gautham M Mar 24 '21 at 05:30
  • Maybe related: [Re-throw an InvocationTargetException target exception](https://stackoverflow.com/questions/10214525/re-throw-an-invocationtargetexception-target-exception). Search for more. – Ole V.V. Mar 24 '21 at 05:36

2 Answers2

2

The problem is that testSaveEmptyApplication is not declared to throw any checked exceptions. But e.getCause() returns Throwable which is a checked exception. So what you are doing in your example code is breaking Java's checked exception rules.

If you know that the cause really is a RuntimeException, then you can do this

throw (RuntimeException) e.getCause();

Caveats:

  • However, if your assumption is incorrect and the cause exception's actual class is a checked exception, the above will result in a (brand new) ClassCastException which squashes the cause exception you were trying to rethrow.

  • The above will also break if the cause was an Error, but you could deal with that; e.g something like this.

     Throwable cause = e.getCause();
     if (cause instanceof RuntimeException) {
         throw (RuntimeException) cause;
     } else if (cause instanceof Error) {
         throw (Error) cause;
     } else {
         throw new AssertionError("Unexpected exception class", cause);
     }
    
  • If you want to be able to rethrow checked exceptions, then they must be declared in the method signature. Once you have done that you can discriminate and throw them as per the above pattern.

This is all a bit cumbersome. But this is the price you pay for having wrapped the exception in the first place.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

One solution I can think of for there is:

The catch clause to be:

try {
  // ...
} catch (Exception e) {
    if(e instanceof UncheckedServiceException) {
        if(e.getCause() instanceof NullPointerException) {
            throw new NullPointerException(e.getCause().getMessage());
       }
    }
}

Otherwise change the method signature like this:

public void method() throws Throwable {
 // ...
}
quarks
  • 33,478
  • 73
  • 290
  • 513