Community
Participate
Working Groups
We are using AspectJ LTW along with Cobertura for code coverage. Class files are weaved just fine if they are not instrumented with Cobertura, but when AspectJ attempts to weave the same aspects into Cobertura-instrumented copies of the same class files, weaving fails with the following error: >> error at com\mycompany\MyAspect.java::0 Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant) The attached project demonstrates the problem. It contains one simple aspect, a target class, and a unit test for the aspect. To see the problem, run the "unittest" target in the included Ant build file. This will run the single unit test twice. In the first pass, the test is run with javac-generated (i.e. uninstrumented) class files. The aspect is correctly woven and the test passes. In the second pass, the test is run with Cobertura-instrumented class files. There is an error during LTW, and the test fails.
The example project zip file is too big for bugzilla, I will make it available elsewhere and provide a link.
The example project is available here: http://github.com/scottfrederick/aspectj-cobertura-example.
the problem here is that Cobertura has moved the start positions of all the local variable table entries. Instead of starting at 0 they now start at 6. AspectJ uses the rule that variables defined from position 0 are the names of the parameters. LocalVariableTable: Start Length Slot Name Signature 6 40 0 this Lcom/example/ExampleAspect; 6 40 1 pjp Lorg/aspectj/lang/ProceedingJoinPoint; 6 40 2 __cobertura__line__number__ I 6 40 3 __cobertura__branch__number__ I Cobertura has inserted extra bytecode ahead of the main code, but that doesn't mean that 'this' and 'pjp' should be moved, since they are defined from the very start of the method because they are method arguments. I'm not sure what I want to do about this right now. However, the workaround is to define the argument names in the advice annotation - that works. @Around(value = "monitorDoSomething()",argNames="pjp") public Object aroundMonitorDoSomething(ProceedingJoinPoint pjp) throws Throwable {
let me know what you think of that workaround. It doesn't seem unreasonable for that to be required if the code is going to be modified by a third party. I can make AspectJ just take the first parameters in the method that make sense for it (skipping 'this' for static contexts) but that does seem a bit fragile since I may just be grabbing local variable names and not parameter names.
I will also take a look at the Cobertura code and see if I can figure out why they modify the code in the way they do, and if it is possible to change Cobertura. I will let you know what I find out. Thanks for researching this.
FWIW, this bug has also bitten us - using AspectJ 1.6.4 and Cobertura 1.9.3. Interestingly enough, we were previously using LTW from Aspectwerkz 2.0 with Cobertura, and did not suffer these problems. We have been stuck on Aspectwerkz for over a year because the LTW in AspectJ did not work properly when previously evaluated. I know Aspectwerkz project has folded into AspectJ now. Does looking at how Aspectwerkz does its LTW (which works with Cobertura) offer any solution that can be used to get AspectJ LTW to also work with Cobertura?
anything I do is a workaround for what cobertura is doing to the bytecode (see comment 3). I don't need to see what Aspectwerkz did to understand what to do, AspectJ is being more strict and expecting particular (as produced by compilers) input - the fix would be to cope with unusual input like this, if cobertura isn't going to adjust the output it produces.
I should add - with this only being hit now and again and not having any votes, I haven't put any time into it. thanks for letting me know you are also hitting it, I will raise the priority because of that.
Andy, I took Scott Frederick's code, replaced the TestNG test case with a Cactus test, performed the changes you suggested and ran it from within the Tomcat container. It failed for the same reason ( [cactus] [WebappClassLoader@165b7e] error at com\example\ExampleAspect.java::O Cannot read debug info for @Aspect to handle formal binding in pointcuts). Here's the Byte Code Local variable table: [pc: 6, pc: 21] local: this index: 0 type: com.example.ExampleAspect [pc: 6, pc: 21] local: __cobertura__line__number__ index: 1 type: int [pc: 6, pc: 21] local: __cobertura__branch__number__ index: 2 type: int @org.aspectj.lang.annotation.Around(value="monitorDoSomething()", argNames="pjp") public java.lang.Object aroundMonitorDoSomething(org.aspectj.lang.ProceedingJoinPoint pjp) throws java.lang.Throwable; Thoughts???
I recall that error about missing debug information coming out for the wrong reasons sometimes. On a quick look I could only find bug 202088 which has been fixed for a while. I will try and find some time to work around what cobertura is doing, but it is likely to take me a couple of weeks to get to it.
I've committed the fix for enabling AspectJ to cope with the quirky bytecode that cobertura creates. There is no flag to turn on as the function that goes searching for the argument names only kicks in if they aren't found where they are supposed to be. The fix is in the currently available dev build.
Works like charm! Thanks a lot for doing this Andy. Just a side note for others working on projects involving Cactus, Cobertura and Aspectj - Cobertura serialized file thats used to store the coverage information is getting locked and I will have to investigate why thats happening (multiple JVMs perhaps).
There is one other thing Cobertura is doing in some cases that's causing AspectJ to mishandle the byte code. Developers might find it useful. Aspect J expects the Byte code's local variable table data to be in the following order (example code) Local variable table: [pc: 6, pc: 21] local: this index: 0 type: com.example.ExampleAspect [pc: 6, pc: 21] local: __cobertura__line__number__ index: 1 type: int [pc: 6, pc: 21] local: __cobertura__branch__number__ index: 2 type: int [pc: 10, pc:121] local: key: 3 type: String Cobertura changes the byte code (instruments) and sometimes the order of the above variables get mixed. Local variable table: [pc: 10, pc:121] local: key: 3 type: String [pc: 6, pc: 21] local: this index: 0 type:com.example.ExampleAspect [pc: 6, pc: 21] local: __cobertura__line__number__ index: 1 type: int [pc: 6, pc: 21] local: __cobertura__branch__number__ index: 2 type: int This is causing AspectJ to not behave properly resulting in "error at com.example.ExampleAspectjava::0 Cannot read debug info for @Aspect to handle formal binding in pointcuts (please compile with 'javac -g' or '<javac debug='true'.../>' in Ant)...." Recommendation 1: Cobertura folks need to fix the way instrumentation is performed so that the local variable table data order is retained Recommendation 2: AspectJ LTW would have to look at the index field values of the local variables rather than assuming that the local variable entries are always added (to the byte code) in the increasing order of the index field values Recommendation 3: Work around: Instead of coding the logic within the Aspect method, re-factor the logic into a new method. @Around(XXXXXX) public Object aspectAround(ProceedingJoinPoint pjp,.....) { return logic(); } public Object logic() { String key = "XYZ"; // some more logic return key; }