Using Clojure with AspectJ's around advices

Context

I wanted to make a call chain, using clojure. And I wanted to track calls to methods of a given Class (the entire service layer, in this case). Using plain Java, the way to tackle this was to use AspectJ, insert a pointcut and an advice, like this:

public aspect MyAspect
{
    pointcut allServiceCalls(): execution(* server.ServiceImpl*(..));
    before(): allServiceCalls() {
        System.out.println(thisJoinPointStaticPart.getSignature().getName());   
    }
}

To use a clojure call to register this call would be trivial, Just use the method I wrote about in the last post, and place the call where the System.out.println is. Simple, right? Let’s move on to where I spend a bit more time figuring my way out: around advices.

The Problem

An around advice, in AspectJ, is much like a before or after advice, except that the advice is responsible for calling proceed();. In order to compute the depth, the easiest way would be to use a dynamically bound variable, update it before calling proceed, and reverting it to its previous value afterwards. In languages like Common Lisp this would be trivial: call defvar to specify a dynamic variable, and use the let macro wrapping the call itself, updating the dynamic variable. But Java won’t allow this behavior, as the proceed(); call is a blackbox, enclosed, and has access only to its parameters, its instance and its parents'. Not to variables that were on the same frame of its call.

So I thought clojure should help, bringing a bit of lisp magic. As it turns out, the binding keyword, used like let, allows us to change dynamic variables, thread-scoped. Perfect! So we just make a before and an after method, and we’re good to go. Wait, but then I can’t wrap them on the clojure side, they’re on different frames, so the binding won’t be able to wrap the proceed(); call… We must definitely use the around advice! But in aspectJ, the proceed is a special keyword, so we won’t be able to use it directly in Clojure. Sure, we could dig around in the aspectJ’s more comprehensive (read: longer, uglier) syntax and use a more primitive way to make the call.

Ahh, if only I could pass a lambda with that computation as an argument to the clojure code… Wait, that’s it! Though not really as practical nor as pretty as Lisp’s lambda notation, Java does allow us to capture behaviour: just make an inline class instance sporting a method to perform the computation! In fact, Java already contains java.lang.Runnable to do just that. Let’s use it, then.

The Solution

Let’s create a subclass of Runnable, so that we may store the computed value and retrieve it later:

package test;
public abstract class AroundWorker implements Runnable {
    private Object returnValue;
    public Object getReturnValue() {
        return returnValue;
    }
    public void setReturnValue(Object returnValue) {
        this.returnValue = returnValue;
    }
}

Now we can use this worker to encapsulate the call to proceed, like this:

public aspect MyAspect
{
    pointcut allServiceCalls(): execution(* server.ServiceImpl*(..));
    Object around(): allServiceCalls() {
        test.AroundWorker worker = new test.AroundWorker() {
            public void run() {
                    this.setReturnValue(proceed());
            }
        };
        my.namespace.markCall(worker, 
            thisJoinPointStaticPart.getSignature().getName());  
        return worker.getReturnValue();
    }
}

Perfect! The variable worker is just like a lambda definition. Yes, I’d rather use (lambda () (proceed)), but it’s Java we’re talking about. I’m glad just for being able to do what I want :)

Now the Clojure part of the code is simple, I’ll just write it down to illustrate how bindings can be used to help us on this problem:

(ns my.namespace
(:gen-class
    :name my.namespace
    :methods [#^{:static true} [markCall [Runnable String] void]]))
(def *current-depth-level* 0)
(defn mark-call
    "Registers a call event, printing its depth level."
    [runnable fn-name]
    (binding [*current-depth-level* (+ *current-depth-level* 1)]
        (println (format "=> current-depth-level %s: %s" 
                            *current-depth-level*
                            fn-name))
        (.run runnable)))
(defn -markCall [& args] (apply mark-call args))

There you go. Run it, and you should see your calls being identified with the proper call depth level. Notice again how I make a wrapper function, exported to the Java world, the encapsulates a clojure one. This allows me to fire up a swank server on the clojure side, and making changes to mark-call at will, without having to recompile the uberjar and reloading/recompiling the java classes. Priceless! :)

The future

It’s completely out of my scope and time-frame for my current project, but it would be great to be able to do this kind of advices directly, without having to resort to aspectJ. If anyone knows about ongoing projects to do this on clojure, please, do leave a comment, I’d be glad to give it a test!