What is the Gradle idiom most similar to the AspectJ @Around annotation?


(Michael Ottati) #1

I would like to surround a test task with a resource monitor. For readers familiar with AspectJ, I am attempting to do something similar to what the AspectJ @Around annotation does below:

@Around("execution(void aspects.TestAspect.myTest())")
public void aroundMyTest(ProceedingJoinPoint joinPoint) throws Throwable {
    System.err.println("Running monitor before test" + joinPoint); 
    monitor();
        joinPoint.proceed();
    monitor();
    System.err.println("Ran monitor after test " + joinPoint); 
}

This can be done rather straightforwardly in Gradle with something like:

test.dependsOn monitorTask
test.finalizedBy monitorTask

Unfortunately Gradle considers this to be a circular dependency.

Circular dependency between the following tasks:
:monitorTask
\--- :test
     \--- :monitorTask (*)

To get around this, I have duplicated my monitorTask and I now have code that looks like:

test.dependsOn monitorTask
test.finalizedBy monitorTask2

The goal I am trying to achieve is that the monitor code runs immediately before a test and immediately after. This might also be possible with:

test.doFirst { monitorTask.execute() }
test.doLast { monitorTask.execute() }

Execution of of tasks in that manner is however is not allowed.

The monitor code I am trying to run collects statistics about the service I am running the test against for later comparative analysis (did the heap grow, how much CPU was used, …). For this reason, I would like my monitor to run immediately before a test runs, and then immediately after.

Is there a better way to implement this than what I have already done?

task monitorTask(type: JavaExec) {
    main = "com.monitor.Monitor"
    classpath sourceSets.main.runtimeClasspath
}

task monitorTask2(type: JavaExec) {
    main = "com.monitor.Monitor"
    classpath sourceSets.main.runtimeClasspath
}

test.dependsOn monitorTask
test.finalizedBy monitorTask2

(Rodrigo B. de Oliveira) #2

Hi Michael,

Another possibility is to use the TaskExecutionGraph API:

 gradle.taskGraph.beforeTask { task ->
   if (task == test) println "before"
 }
 gradle.taskGraph.afterTask { task ->
   if (task == test) println "after"
 }

Cheers,
Rodrigo


(Michael Ottati) #3

Rodrigo:

Thank you, your example appears to closely mimic the @Around annotation. That solves half of my problem.

The second part of the problem remains. There is no way to programatically invoke a task, which in our use case, is what we want to do, both before and after the test task.

Our real life use case has rather complex class path requirements which are most conveniently declared within a task. We also use this task on it’s own to take samples. Is there any way you you can think of to invoke the monitor task in your code sample where you print the before and after messages?


(Mark Vieira) #4

I’m not sure if there is any specific reason why this logic needs to live inside a task. It doesn’t have any dependencies, doesn’t product (traditional) output so it wouldn’t really benefit from being a task. Just add a doFirst() and doLast() with the monitoring code (the task implementation) and call it a day I say. You can do this easily w/o a task by using project.exec().