Community
Participate
Working Groups
AspectJ 1.5.2 compiles this code without error, whereas the declare soft shouldn't have any effect, in particular it shouldn't allow the run() method on the anonymous class to throw an undeclared checked exception. Interestingly the runtime catch and coversion to a SoftException is NOT performed in this case, just removing the need to declare the exception. import java.sql.SQLException; public class SoftenInner { public static void main(String args[]) { new SoftenInner().foo(); } public void foo() { new Runnable() { public void run() { throw new SQLException("test"); } }.run(); } } public aspect Softener { declare soft: Throwable: execution(* SoftenInner.foo()); }
The reason the test program is compiling without any errors is because by the time org.aspectj.ajdt.internal.compiler.problem.AjProblemReporter.unhandledException(..) is called the referenceContext is the method foo() rather than run(). Consequently, we match the pointcut "execution(* SoftenInner.foo())" with "public void foo()". This always matches and so we return from unhandledException(..) thinking that the declare soft is softening this exception. The referenceContext changes in the call scope.problemReporter() where scope is the MethodScope for run() (FlowContext line 275). This starts with the run() method and then moves outwards recording the last known method until it reaches null. In this case the last known method is foo() and so this is returned.
Some observations: 1. if we add "public void run() throws SQLException" then we get the "exception not compatible with throws clause in Runnable.run()" compilation error (as expected) 2. if have "declare soft: Throwable :execution(* Runnable.run())" then get an unchecked exception (because the outer method is foo and we see if the pointcut matches executions of foo which it doesn't) 3. if add the "throws SQLException" then with run in pointcut we get both error messages 4. Without any declare soft...the only error message is the one about the unhandled exception. As expected, the following compiles with javac: ---------------------------------------------------- public class C implements I { public void foo() throws RuntimeException { } } interface I { public void foo(); } ---------------------------------------------------- Essentially though, this is what the declare soft is doing. According to the documentation of declare soft: "An aspect may specify that a particular kind of exception, if thrown at a join point, should bypass Java's usual static exception checking system and instead be thrown as a org.aspectj.lang.SoftException, which is subtype of RuntimeException and thus does not need to be declared." Therefore, it seems from this definition that one wouldn't expect to get the unhandled exception when declare soft is applied to a method which throws an exception not compatible with the method it overrides. However, the question is whether declare soft: Throwable: execution(* SoftenInner.foo()); or declare soft: Throwable :execution(* Runnable.run()); (or both) should soften the "throw new SQLException()".
I think declare soft: Throwable :execution(* Runnable.run()); should soften it and not declare soft: Throwable: execution(* SoftenInner.foo()); And I know we have had problems in the past with problemReporter() executing in an incorrect scope.
I believe this is an extension to bug 125981. Porting the fix proposed in that bug to the other FlowContext.checkExceptionHandlers method ensures the behaviour expected in comment #3.
Created attachment 50693 [details] testcase and fix The attached zip contains the following: * pr151772-tests.txt: apply to the tests project * FlowContext.java: to replace org.aspectj.org.eclipse.jdt.internal.compiler.flow.FlowContext. Together these contain the testcases and fix both for this bug and bug 125981.
Fix has been applied and is in latest AJ dev build (Build.824 - 09/22/2006 17:59:43)
fix available.
Updated org.aspectj/bundles.
iplog