Search code examples
javaapache-sparkaspect

AspectJ 1.9.4 with OpenJDK 11 Without Spring Context not working as a dependent module on Spark routes


I am trying to create custom loadtime annotations with AspectJ, Open JDK11 without Spring Context. It works fine within a module and annotations are weaving at class load time and aspects are executing at runtime. No issues, But when aspectJ implemented module added as a dependency on another module with spark routes. AspectJ and annotations are not processing. Am I missing any configuration?

Parent POM:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>de.scrum-master</groupId>
  <artifactId>aspectj-ltw-test-multi-module</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.source-target.version>11</java.source-target.version>
    <aspectj.version>1.9.4</aspectj.version>
  </properties>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.3</version>
          <configuration>
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <!-- IMPORTANT -->
            <useIncrementalCompilation>false</useIncrementalCompilation>
          </configuration>
        </plugin>
        <plugin>
          <groupId>com.nickwongdev</groupId>
          <artifactId>aspectj-maven-plugin</artifactId>
          <version>1.12.1</version>
          <configuration>
            <!--<showWeaveInfo>true</showWeaveInfo>-->
            <source>${java.source-target.version}</source>
            <target>${java.source-target.version}</target>
            <Xlint>ignore</Xlint>
            <complianceLevel>${java.source-target.version}</complianceLevel>
            <encoding>${project.build.sourceEncoding}</encoding>
            <!--<verbose>true</verbose>-->
            <!--<warn>constructorName,packageDefaultMethod,deprecation,maskedCatchBlocks,unusedLocals,unusedArguments,unusedImport</warn>-->
          </configuration>
          <executions>
            <execution>
              <!-- IMPORTANT -->
              <phase>process-sources</phase>
              <goals>
                <goal>compile</goal>
                <goal>test-compile</goal>
              </goals>
            </execution>
          </executions>
          <dependencies>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjtools</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
            <dependency>
              <groupId>org.aspectj</groupId>
              <artifactId>aspectjweaver</artifactId>
              <version>${aspectj.version}</version>
            </dependency>
          </dependencies>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.9</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
      </dependency>
      <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
      </dependency>
      <dependency>
        <groupId>de.scrum-master</groupId>
        <artifactId>aspect</artifactId>
        <version>1.0-SNAPSHOT</version>
      </dependency>
      <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <modules>
    <module>aspect</module>
    <module>application</module>
  </modules>

</project>

Aspect module:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>de.scrum-master</groupId>
    <artifactId>aspectj-ltw-test-multi-module</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <groupId>de.scrum-master</groupId>
  <artifactId>aspect</artifactId>
  <version>1.0-SNAPSHOT</version>

  <build>
    <plugins>
      <plugin>
        <groupId>com.nickwongdev</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
    </dependency>
  </dependencies>
</project>
<aspectj>
  <aspects>
    <aspect name="de.scrum_master.aspect.CounterAspect"/>
  </aspects>
  <weaver options="-verbose">
    <!-- weave anything -->
    <include within="*"/>
  </weaver>
</aspectj>
package de.scrum_master.aspect;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented
@Inherited
@Target(METHOD)
@Retention(RUNTIME)
public @interface Counter {
  String name() default "";
}
package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class CounterAspect {
  @Around("execution(* *.*(..)) && @annotation(counter)")
  public void myBeforeLogger(ProceedingJoinPoint joinPoint, Counter counter) {
    System.out.println(joinPoint + " -> " + counter.name());
  }
}

Application module:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <parent>
    <groupId>de.scrum-master</groupId>
    <artifactId>aspectj-ltw-test-multi-module</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>

  <groupId>de.scrum-master</groupId>
  <artifactId>application</artifactId>
  <version>1.0-SNAPSHOT</version>

  <dependencies>
    <dependency>
      <groupId>de.scrum-master</groupId>
      <artifactId>aspect</artifactId>
    </dependency>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <scope>test</scope>
    </dependency>
     <dependency>
        <groupId>com.sparkjava</groupId>
        <artifactId>spark-core</artifactId>
        <version>2.9.0</version>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <argLine>
            -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
          </argLine>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>
package de.scrum_master.app;

import de.scrum_master.aspect.Counter;

public class MyCounter {
  @Counter(name = "call_count")
  public void count() {}
}
package de.scrum_master.app;

import spark.Spark;
import static spark.Spark.get;

public class CounterApp {

 public static void main(String[] args) {
    get("/counter", (req, res) -> {
         new MyCounter().count();
         return "I ALREADY CALLED COUNTER ASPECT ON METHOD:MyCounter().count()";
    });
    System.out.println("Application starting on port :"+ Spark.port());

 }

}

NOTE: If i call below URL my annotation should be processed. But it is not!

http://localhost:4567/counter


Solution

  • Well, first you forgot to add Spark Core to your application module's dependencies, you only defined the version in the parent POM's dependency management section. Otherwise the Maven project will not even compile because of the unknown imports.

    Furthermore, the same I told you in my comment to your first question applies:

    You attach the Java agent via command line, just like you do for the test.

    As an example I added Exec Maven plugin to your application POM and configured it to run your sample main class:

    <!-- (...) -->
    
      <properties>
        <main-class>de.scrum_master.app.CounterApp</main-class>
      </properties>
    
    <!-- (...) -->
    
          <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>exec-maven-plugin</artifactId>
            <configuration>
              <executable>java</executable>
              <arguments>
                <argument>
                  -javaagent:${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar
                </argument>
                <argument>-classpath</argument>
                <!-- automatically creates the classpath using all project dependencies, also adding the project build directory -->
                <classpath/>
                <argument>${main-class}</argument>
              </arguments>
            </configuration>
          </plugin>
    
    <!-- (...) -->
    

    Then you run your build and subsequently run the application:

    $ mvn clean install
    (...)
    
    $ cd application
    
    $ mvn exec:exec
    (...)
    [INFO] --------------------< de.scrum-master:application >---------------------
    [INFO] Building application 1.0-SNAPSHOT
    [INFO] --------------------------------[ jar ]---------------------------------
    [INFO]
    [INFO] --- exec-maven-plugin:1.4.0:exec (default-cli) @ application ---
    [AppClassLoader@2aae9190] info AspectJ Weaver Version 1.9.4 built on Friday May 10, 2019 at 08:43:10 PDT
    [AppClassLoader@2aae9190] info register classloader jdk.internal.loader.ClassLoaders$AppClassLoader@2aae9190
    [AppClassLoader@2aae9190] info using configuration file:/C:/Users/alexa/.m2/repository/de/scrum-master/aspect/1.0-SNAPSHOT/aspect-1.0-SNAPSHOT.jar!/META-INF/aop.xml
    [AppClassLoader@2aae9190] info register aspect de.scrum_master.aspect.CounterAspect
    (...)
    Application starting on port :4567
    [AppClassLoader@2aae9190] warning javax.* types are not being woven because the weaver option '-Xset:weaveJavaxPackages=true' has not been specified
    (...)
    [AppClassLoader@2aae9190] info processing reweavable type de.scrum_master.aspect.CounterAspect: de\scrum_master\aspect\CounterAspect.aj
    [AppClassLoader@2aae9190] info successfully verified type de.scrum_master.aspect.CounterAspect exists.  Originates from de\scrum_master\aspect\CounterAspect.aj
    

    Then call your URL http://localhost:4567/counter and check the console output of your running server:

    execution(void de.scrum_master.app.MyCounter.count()) -> call_count
    

    The full commit I added to the repository generated for the previous question is here.