Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[ajdt-dev] Some @aspectj advices leading to some runtime errors

Hi list,

Glad to use AspectJ in one of our project!

[I use AJDT 2.2.0.e37x-20120105-1100 with AspectJ version: 1.7.0.20111215190600 in my IDE. And AspectJ 1.6.12 in my production environment]

I encounter some problems with using @aspectj.
I define the following example class in a simple AspectJ project.

<code>
package foo;

public class Test {

        public final static void main(String[] args) {
                Test test = new Test();
                System.out.println(test.runTest());
        }

        public int runTest() {
                return this.test(5);
        }

        public int test(int i) {
                return i;
        }
}
</code>

Then I tried different way of pointcuting the int test(int) method. I describe each time what I observe bellow.

1. Using neither args() nor this()

<code>
package foo;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TestAspect {

        @Pointcut("call(int foo.Test.test(int)) && "
                        + " target(test)")
        void testPointcut(Test test) {}

        @Around("testPointcut(test)")
        public Object doTest(final ProceedingJoinPoint jp,
                        Test test) throws Throwable {
                return jp.proceed(new Object[] { test });
        }
}
</code>

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1
        at foo.Test.test_aroundBody1$advice(Test.java:18)
        at foo.Test.runTest(Test.java:11)
        at foo.Test.main(Test.java:7)


2. Using args() but no this()

>From reading the docs this code is correct.

<code>
package foo;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TestAspect {

        @Pointcut("call(int foo.Test.test(int)) && "
                        + " target(test) && args(i)")
        void testPointcut(Test test, int i) {}

        @Around("testPointcut(test, i)")
        public Object doTest(final ProceedingJoinPoint jp,
                        Test test, int i) throws Throwable {
                return jp.proceed(new Object[] { test, i * 2 });
        }
}
</code>

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to foo.Test
        at foo.Test.test_aroundBody1$advice(Test.java:18)
        at foo.Test.runTest(Test.java:11)
        at foo.Test.main(Test.java:7)

3. Using args() and this()

<code>
package foo;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class TestAspect {

        @Pointcut("call(int foo.Test.test(int)) && "
                        + " target(test) && args(i)")
        void testPointcut(Test test, int i) {}

        @Around("testPointcut(test, i) && this(t)")
        public Object doTest(final ProceedingJoinPoint jp,
                        Test test, int i, Object t) throws Throwable {
                return jp.proceed(new Object[] { t, test, i * 2 });
        }
}
</code>

This version works as expected. However, it seems that the generated bytecode during weaving incorrectly builds the debug line markers as if you put a breakpoint in the advice, Eclise don't suspend inside the advice code but elsewhere in the Test class code. Also, when you try to step (in a blind way) in the code from a breakpoint in runTest(), you can observe there is somewhat a mismatch in the variable handling...

Should I raise a bug for all that ?

After playing with AspectJ source code (version 1.6.12), I suspect there might be a bug in the weaver but also in line 202 of JoinPointImpl:

state[hasThis ? 1 : 0] = adviceBindings[hasThis ? 1 : 0];

Shouldn't this be :

state[hasThis ? 1 : 0] = adviceBindings[bindThis ? 1 : 0];

Everytime you can replace the faulty proceed(..) call by a no-arg proceed() call and then this works as expected.

Thanks for you help!
Didier.aj


Back to the top