kotlingradleaspectjfreefair-aspectj

Freefair in a multimodule Kotlin project


I'm using the io.freefair.aspectj.post-compile-weaving plugin in my Kotlin-Gradle multi-module project to enable aspects in my springboot application.

When I tried using the plugin in a simple project it worked perfectly fine, when I then split the project into a multi-module one, it started simply not recognizing the aspects anymore

Here is a MCVE I created on github.

So I basically setup the root project gradle file:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "3.1.5"
    id("io.spring.dependency-management") version "1.1.3"
    id("io.freefair.aspectj.post-compile-weaving") version "6.6.3"
    kotlin("jvm") version "1.8.22"
    kotlin("plugin.spring") version "1.8.22"
}

group = "com.voiddev"

allprojects {
    apply(plugin = "org.jetbrains.kotlin.jvm")
    apply(plugin = "kotlin-spring")
    apply(plugin = "io.spring.dependency-management")
    apply(plugin = "org.springframework.boot")
    apply(plugin = "io.freefair.aspectj.post-compile-weaving")

    version = "0.0.1-SNAPSHOT"
    java {
        sourceCompatibility = JavaVersion.VERSION_17
    }

    repositories {
        mavenCentral()
    }

    dependencies {
        implementation("org.springframework.boot:spring-boot-starter-web")
        implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
        implementation("org.jetbrains.kotlin:kotlin-reflect")
        testImplementation("org.springframework.boot:spring-boot-starter-test")

        implementation("org.aspectj:aspectjrt:1.9.19")
    }

    tasks.withType<KotlinCompile> {
        kotlinOptions {
            freeCompilerArgs += "-Xjsr305=strict"
            jvmTarget = "17"
        }
    }

    tasks.withType<Test> {
        useJUnitPlatform()
    }
}

Then all I do is try to use the aspects defined in the 'common' module, within the 'server' module. I did import correclty the common module within the server module, since I'm able to access the classes defined in the common module. This is my server gradle file:

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "3.1.5"
    id("io.spring.dependency-management") version "1.1.3"
    id("io.freefair.aspectj.post-compile-weaving") version "6.6.3"
    kotlin("jvm") version "1.8.22"
    kotlin("plugin.spring") version "1.8.22"
}

group = "com.voiddev"

dependencies {
    implementation(project(":common"))
}

tasks {
    bootJar {
        archiveBaseName.set(rootProject.name)
    }
}

However the aspects are simply ignored


Solution

  • Actually, I am wondering why you use native AspectJ at all, because you apply the aspect to a Spring service. I.e., the regular "AOP lite" called Spring AOP, which comes with Spring, would suffice. For that, you do not need any extra build plugins.

    Anyway, to answer your question: Your module common is an aspect library. To make the AspectJ compiler recognise it as such, you ought to put it on the aspectpath, not on the regular classpath. In Freefair, as documented here, this is done like this:

    dependencies {
      aspect(project(":common"))
    }
    

    Then, it works. Given this server application, ...

    @SpringBootApplication
    class ServerApplication
    
    fun main(args: Array<String>) {
      runApplication<ServerApplication>(*args).use {
        println(it.getBean(AspectService::class.java).randomFunction())
      }
    }
    

    ... the console log will be:

    MetricAspect: $Proxy57
    MetricAspect: $Proxy57
    Hello Aspect
    

    But of course, your pointcut is too generic when using native AspectJ. It will match twice, once for call and once for execution joinpoints. That would not happen in Spring AOP, because the latter only knows execution. You can fix it like this:

    @After("@annotation(metricAnnotation) && execution(* *(..))")
    

    The console log changes to:

    MetricAspect: $Proxy57
    Hello Aspect
    

    You might also want to optionally consider upgrading the Freefair plugin from 6.6.3 to 8.4 in both modules:

    id("io.freefair.aspectj.post-compile-weaving") version "8.4"