Summary: | Inner Aspects: Compiler complains about exceptions when the join point does not throw an exception | ||
---|---|---|---|
Product: | [Tools] AspectJ | Reporter: | Uli Eibauer <ueno.4> |
Component: | Compiler | Assignee: | aspectj inbox <aspectj-inbox> |
Status: | RESOLVED FIXED | QA Contact: | |
Severity: | normal | ||
Priority: | P3 | ||
Version: | 1.2.1 | ||
Target Milestone: | --- | ||
Hardware: | PC | ||
OS: | Linux | ||
Whiteboard: |
Description
Uli Eibauer
2006-05-15 06:30:07 EDT
// ==> 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... |