Community
Participate
Working Groups
//initial situation: class Table { void foo() throws CheckedException { .. bar(session, mode, data1, data2); check(session,data2); .. } void bar(Session session, int mode, Object[] data1, Object[] data2) {..} void check(Session session, Object[] data2) throws CheckedException {..} } //situation after aspect oriented refactoring class Table { void foo() throws CheckedException { .. bar(param1, param2); .. } void bar(Session session, int mode, Object[] data1, Object[] data2) {..} void check(Session session, Object[] data2) throws CheckedException {..} private static aspect AccessControlAspect { after(Session session, int mode, Object [] data, Table table) returning : call(* *..Table.bar(Session, int, Object[], Object[])) && withincode(* *..Table.foo(..)) && args(session, mode, *, data) && target (table) { table.check(session, data); } } // ==> Realizing this situation as shown above results in a compiler error, // 'unhandled exception CheckedException' // when calling table.check(..) within the advice // ==> Adding 'throws CheckedException' to the advice declaration results in a // compiler error, // 'can't throw checked Exception CheckedException at this join point' //==> Realizing the aspect as outer aspect works fine
// ==> Realizing this situation as shown above results in a compiler error, // 'unhandled exception CheckedException' // when calling table.check(..) within the advice // ==> Adding 'throws CheckedException' to the advice declaration results in a // compiler error, // 'can't throw checked Exception CheckedException at this join point' both of these messages are correct. As described in the semantics guide, advice can only throw checked exceptions that are declared in its throws clause, and only at join points that are declared to throw the given checked exception. Since "check" can throw a checked exception, you must either handle that exception inside the advice body, or declare the checked exception in the advice signature. If a checked exception can be thrown by advice (declared in the signature), then you can only advise join points at which the checked execption is declared (otherwise you would be breaking the contract expected by e.g. the caller of bar in this case, since that caller is not expecting a call to bar to raise a CheckedException). So what matters is that the call to bar doesn't raise an exception bar is not declared to throw - not whether or not this call happens within a method that has the corresponding exception in its own throws clause. If there is a bug here at all, it is that you didn't get a similar message when declaring the aspect as a top-level type. Was your aspect *identical* to the one shown when you did that? The following simplified version of your scenario does indeed produce the expected error messages with a top-level aspect: class CheckedException extends Exception {} class Table { public void foo() throws CheckedException { bar(); } public void bar() {} public void check() throws CheckedException {} } aspect A { after(Table t) returning throws CheckedException : call(* bar()) && target(t) && withincode(* Table.foo(..)) { t.check(); } } Compiling with ajc gives: /Users/adrian/projects/aj-play/Table.java:6 [error] can't throw checked exception 'CheckedException' at this join point 'method-call(void Table.bar())' bar(); ^^^^^ /Users/adrian/projects/aj-play/Table.java:17 [error] can't throw checked exception 'CheckedException' at this join point 'method-call(void Table.bar())' after(Table t) returning throws CheckedException : call(* bar()) && target(t) && withincode(* Table.foo(..)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 2 errors
Thanks for your quick answer! I re-checked the solution as outer advice and the result is also as you described. I understand the programming by contract issue and you are definitely right not to permit throwing checked exceptions in such a case. I am currently doing a refactoring project on an existing software tool. So I had the "refactoring" point of view and from this point of view it definitely means a restriction that you cannot translate this situation one by one. Throwing a soft exception and unwrapping it is really not very comfortable. Exception handling within the advice is not what the original program flow meant to be.
I agree with you here. When I was working through your scenario I could see exactly why you'd want to be able to throw the checked exception from the advice. It certainly complicates the refactoring flow that it can't be done without some additional mechanism to soften or otherwise handle the exception...