Community
Participate
Working Groups
In order to test exception scenarios in an existing framework, I have created an aspect to inject an exception. The exception is injected into some code running within a try/catch/finally block. After the exception is thrown, I am expecting control to pass to the catch block. However, what is happening is that the catch block code is not executed, control passes through the finally block and the (undeclared) exception is thrown to the calling method. Here is a distilled test case: public class MainClass { protected Integer counter; private int j; public static void main(String[] args) { MainClass mh = new MainClass(); try { mh.doSomething(); } catch (Exception e) { System.out.println("Exception thrown by doSomething!!!!!"); e.printStackTrace(); } } public void doSomething() { int i = 0; while (i++ < 1) { counter=null; try { counter = getCounter(); if (counter == null) { break; } commit(); } catch (Throwable e) { System.out.println("Caught exception " + e); } finally { System.out.println("In finally block"); } } } protected Integer getCounter() { return new Integer(j++); } protected void commit() throws SQLException { System.out.println("Main.commit"); } } The following aspect injects the exception: public aspect SimpleExceptionThrowingAspect { pointcut commitOperation() : call (* MainClass+.commit(..)); before() throws SQLException : commitOperation() { throw new SQLException("Dummy SQL Exception", "55102"); } } Expected output is: Caught exception java.sql.SQLException: Dummy SQL Exception In finally block Actual output is: In finally block Exception thrown by doSomething!!!!! java.sql.SQLException: Dummy SQL Exception at nz.govt.moh.test.SimpleExceptionThrowingAspect.ajc$before$nz_govt_moh_test_SimpleExceptionThrowingAspect$1$292c82f1(SimpleExceptionThrowingAspect.aj:10) at nz.govt.moh.test.MainClass.doSomething(MainClass.java:32) at nz.govt.moh.test.MainClass.main(MainClass.java:14) Removing the "break;" statement from MainClass.java causes the expected output to be produced.
This is related to bug 79554 - they are both to do with us creating an incorrect exception table for a woven method. The exception table for the unwoven code is: Exception table: from to target type 9 38 38 Class java/lang/Throwable 9 29 64 any 32 61 64 any 81 84 64 any Once woven, this changes to: Exception table: from to target type 87 90 70 any 32 67 70 any 9 44 44 Class java/lang/Throwable 9 29 70 any The inclusion of 'any' with a range that overlaps the 'Throwable' range is causing the problem. When the exception occurs, it is right in the overlap range and so in the woven code we skip the catch block, do the finally stuff and rethrow the exception.
When unpacking, we associate a priority with entries in the exception table. This priority can be used when writing the class out to ensure we don't break the ordering carefully constructed by the compiler. We currently ignore the priority - leading to situations where sometimes entries for finally blocks obscure entries for real catch blocks. The implementation of the priority for newly created exception handlers (created during weaving) doesn't seem quite right as they are given either super high priority (Integer.MAX) or super low priority (-1). There are comments in the code (around LazyMethodGen.insertHandler()) which suggest what the right long term implementation would be but having spent the last day in the code, it is not trivial and the simpler immediate fix of using the priorities fixes this bug and the related 79954. We can do the full implementation of the priority work when (if?) someone finds a situation that the current algorithm doesn't cope with. Fix checked in - waiting for build.
Fix available: BUILD COMPLETE - build.429 Date of build: 01/11/2005 11:52:16 Time to build: 103 minutes 38 seconds Last changed: 01/11/2005 11:22:16 Last log entry: Fixes for 78021, 79554 - both to do with us breaking the exception table for a method on weaving *if* finally blocks are involved. Latest good AspectJ jar available at: download.eclipse.org/technology/ajdt/dev/aspectj-DEVELOPMENT.jar