4

I am trying to catch an exception that is thrown within my main in my Java class.

My main's code:

public static void main(String[] args){
    new something();
    throw new RuntimeException();
}

In my aspect, I have created both after() returning: execution(* main(*)) { advice} and after() throwing(Exception e): execution(* main(*)) { advice } to find out if an exception is thrown in the main or not, in order to do something different at each advice.

Note that inside the second one, I am printing in the output the e exception using:

System.out.println("Threw an exception: " + e + "Joinpoint: " + thisJoinPoint.getSignature().toString());

The problem is that even if I throw an exception in main, and I can see from the output that the pointcut that is matched is the second one (Ouput: Threw an exception: java.lang.RuntimeExceptionJoinpoint: void main(String[]) ), I still get this error in my output:

Exception in thread "main" java.lang.RuntimeException
    at main(C.java:24)

So, as I can understand, I haven't catched the exception, I just identified that an exception happened in main.

Is there a way that I could catch this exception without having to use around() ?

Marialena
  • 817
  • 8
  • 31

1 Answers1

6

You can't suppress an exception with an after() throwing advice, you'll need to use an around() advice as you suspected.

void around(): execution(* MainClass.main(*)) {
    try {
        proceed();
    } catch (Exception e) {
        //suppress
        System.out.println("Suppressed an exception: " 
            + e + "Joinpoint: " + thisJoinPoint.getSignature().toString());
    }
}

An after() throwing advice is good to run additional code when an exception is thrown at some point of interest of yours but it won't stop the exception from propagating unless you throw another exception from your advice code (wrap the suppressed exception if you do so):

after() throwing(Exception e): execution(* MainClass.main(*)) {
    System.out.println("Threw an exception: " + e + "Joinpoint: " 
        + thisJoinPoint.getSignature().toString());
    throw new RuntimeException("Another exception", e);
}

EDIT: I'm adding an example on how to emulate before(), after() returning, after() throwing and after() advices in an around() advice following up a question in a comment on my answer.

void around(): execution(* MainClass.main(*)) {
    try {
        //before() code
        System.out.println("Before main started.");

        proceed();

        //after() returning code
        System.out.println("Main exited normally.");
    } catch (Exception e) {
        //after() throwing code suppressing exception unless you rethrow it
        System.out.println("Suppressed an exception: " + e + "Joinpoint: " 
            + thisJoinPoint.getSignature().toString());
    } finally {
        //after() code
        System.out.println("After main executed.");
    }
}

This will output the following lines when your main class is run:

Before main started.
Main started.
Suppressed an exception: java.lang.RuntimeException: errorJoinpoint: void MainClass.main(String[])
After main executed

Note that the code for the after() returning part doesn't get executed as your main class doesn't finish normally as it throws an exception instead, just as a normal after() returning advice would not run in that case.

Nándor Előd Fekete
  • 6,988
  • 1
  • 22
  • 47
  • When I tried to use `around`, the rest code inside it, didn't work as it should. It doesn't work either if I have `before()` or `around()`. Is there a way in around() that I could make my code run as it was in `after`? – Marialena Mar 08 '16 at 23:53
  • I'm not sure I understand your question. You want to emulate `after() returning` in an `around()` advice? Or `after() throwing`? Or both at the same time? – Nándor Előd Fekete Mar 08 '16 at 23:55
  • `after() returning` and `after() throwing` have different advice. When I have these implementations like this, both works correctly BUT i can't catch the exception in main in order not to display this exception in the output as error. If I try to combine both in one `around()`, and by that I mean put the code of `after() returning` in the `try{` of `around()` and the code of `after() throwing` in the `catch {` of `around()` it doesn't work as it should, even if I don't throw an exception in my main. If I throw an exception in main I can catch that. – Marialena Mar 09 '16 at 00:02
  • I found out that, the `around()` I have created in order to catch the exception, doesn't work because a second pointcut which is used in another `around()`, for some reason it is affected when I change `after()` or [`after() returning` and `after() throwing`] to `around()` for the above (`execution(* MainClass.main(*))`).. The pointcut of the `around()` that gets affected, is a combination of joinpoints that include `withincode(* main(*)`. – Marialena Mar 09 '16 at 00:16
  • Well, I can't comment on that as I don't see your whole environment, but I edited my answer to include the `around()` advice example you asked for in your previous comments. – Nándor Előd Fekete Mar 09 '16 at 00:20
  • It worked now as I wanted to. In summary, I have added an `around()` which has a `try{}` and a `catch{}`. Within `try{}` the first instruction is `proceed()` so that I can have the code which I had in `after() returning` run properly. The code that I had in `after() throwing`, I placed it in `catch{}`. Now everything works properly even If I have an exception or not. Thank you! – Marialena Mar 09 '16 at 00:25