Today I was writing an AspectJ aspect for a Scala trait and was wondering why my constructor pointcut definition didn’t work. Having a closer look at the Scala byte code together with my colleague Johan solved the puzzle. Here is what I did (using AspectJ 1.6.8 and Scala 2.8.Beta1):
To start with here’s a simplified version of the trait that I wanted to intercept:
trait MyTrait { var someStuff = "someStuff" def someMethod() : String = { "do something" } } class SomeClass extends MyTrait
As I wanted to intercept the constructor and some method calls I defined my aspect like this:
public aspect MyAspect { public pointcut newInstance() : execution(MyTrait+.new(..)); public pointcut someInvocation() : execution(String MyTrait+.someMethod(..)); after() : newInstance() { System.out.println("after MyTrait constructor invocation"); } after() : someInvocation() { System.out.println("after someMethod invocation"); } }
Runnning the code I got quite puzzled that the method invocation pointcut worked fine, but not the constructor pointcut. After consulting the AspectJ reference and convincing myself that the pointcut definition was ok, I had a closer look at the byte code. As we don’t have traits in Java the byte code for my trait becomes equivalent to the following pseudo-javacode:
public interface MyTrait extends scala.ScalaObject{ public String someMethod(); } public abstract class MyTrait$class extends java.lang.Object{ public static String someMethod(MyTrait myTrait) { // invoke someMethod } public static void $init$(MyTrait myTrait) { // some init stuff } }
So in bytecode I’ve got an interface and a class with some static method calls. The stuff that goes in the constructor of my trait is done in the $init$
method of the MyTrait$class
class. And that’s the reason why my pointcut won’t work. So actually I have to intercept the $init$
method of the MyTrait$class
to get what i want:
public pointcut newInstance() : execution(void MyTrait$class.$init$(..));
looks like u’r trying to compromise whole idea behind the traits :D
why don’t u use classes instead :D