Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Post-compile weaving aspects into a project using Gradle

Background

Performing post-compile weaving of projects using:

  • AspectJ 1.9.4
  • io.freefair.aspectj.post-compile-weaving 4.1.1
  • Java 11.0.3
  • Gradle 5.6.2 (Groovy 2.5.4, Kotlin 1.3.41)

This project does not use Maven or Spring.

Layout

The projects include:

  • app.aspects - Contains a single LogAspect class annotated with @Aspect.
  • app.aspects.weaver - No source files, only dependencies to declare aspects and project to weave.
  • app.common - Defines @Log annotation referenced by pointcuts described in LogAspect.
  • app.program.main - Files to be woven with jointpoints described in LogAspect.

Gradle

Build files that relate to aspects are defined here. The idea is that weaving is independent from the application so neither the application's common classes nor the main program need know about weaving. Rather, the main program need only reference @Log from the common package and AJC will take care of the weaving.

app.aspects

apply plugin: "io.freefair.aspectj.post-compile-weaving"

dependencies {
    // For the @Log annotation
    compileOnly project(':app.common')

    // The LogAspect's joinpoint references the Main Program
    compileOnly project(':app.program.main')

    // Logging dependency is also compiled, but not shown here
}

app.aspects.weaver

apply plugin: "io.freefair.aspectj.post-compile-weaving"

dependencies {
    compileOnly "org.aspectj:aspectjrt:1.9.4"

    // This should set the -aspectpath ?
    aspect project(":app.aspects")

    // This should set the -inpath ?
    inpath(project(":app.program.main")) {
        // Only weave within the project
        transitive = false
    }
}

Classes

Log

The Log annotation is straightforward:

package com.app.common.aspects;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE, ElementType.CONSTRUCTOR })
public @interface Log {
    boolean secure() default false;
}

Main Program

The main program resembles:

package com.app.program.main;

import com.app.common.aspects.Log;

@Log
public class Program {

  /** This is the method to weave. */
  protected void run() throws InterruptedException, TimeoutException {
  }
}

Logging Aspect

The logging aspect resembles (see the code from a related question):

@Aspect
public class LogAspect {

    // In the future this will target points annotated with @Log
    @Pointcut("execution(* com.app.program.main.Program.run(..))")
    public void loggedClass() {
    }

    @Around("loggedClass()")
    public Object log(final ProceedingJoinPoint joinPoint) throws Throwable {
      return log(joinPoint, false);
    }

    private Object log(final ProceedingJoinPoint joinPoint, boolean secure) throws Throwable {
      // See last year's code for the full listing
      log.info("\u21B7| {}{}#{}({})", indent, className, memberName, params);
    }
}

Problem

It appears weaving is taking place, but the advice cannot be found:

.../app.aspects/build/classes/java/main!com/app/aspects/LogAspect.class [warning] advice defined in com.app.aspects.LogAspect has not been applied [Xlint:adviceDidNotMatch]

Question

What needs to change so that weaving of the LogAspect into Program's run() method works using Gradle?

Options File

The ajc.options file shows:

-inpath
.../app.aspects/build/classes/java/main
-classpath
.../.gradle/caches/modules-2/files-2.1/org.aspectj/...
-d
.../app.aspects/build/classes/java/main
-target
11
-source
11

It is disconcerting that -aspectpath isn't shown and -inpath is listing app.aspects instead of app.program.main.

like image 858
Dave Jarvis Avatar asked Nov 06 '22 13:11

Dave Jarvis


1 Answers

Merging apps.aspects and apps.aspects.weaver into the same project has produced:

Join point 'method-execution(void com.app.program.main.Program.run())' in Type 'com.app.program.main.Program' (Program.java:396) advised by around advice from 'com.app.aspects.LogAspect' (LogAspect.class(from LogAspect.java))

While this solves the problem, I don't understand why LogAspect needs to be in the same project that performs the weaving. The Gradle file becomes:

apply plugin: "io.freefair.aspectj.post-compile-weaving"

dependencies {
    compileOnly "org.aspectj:aspectjrt:1.9.4"
    compileOnly project(':app.common')
    compileOnly project(':app.program.main')

    compileOnly org_apache_logging_log4j__log4j_api

    inpath(project(":app.program.main")) {
        transitive = false
    }
}

compileJava.ajc.options.compilerArgs += "-showWeaveInfo"
compileJava.ajc.options.compilerArgs += "-verbose"
like image 103
Dave Jarvis Avatar answered Nov 12 '22 18:11

Dave Jarvis