Intercepting Scala trait constructors

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$(..));

This Post Has One Comment

  1. looks like u’r trying to compromise whole idea behind the traits :D

    why don’t u use classes instead :D

Leave a Reply

Close Menu