Skip to content

Compiler error when extending aspect with static 'if()' pointcut in @AspectJ syntax during binary weaving #338

@kriegaex

Description

@kriegaex

Preface

Originally reported as mojohaus/aspectj-maven-plugin#222, the issue is unrelated to AspectJ Maven Plugin. Therefore, I am creating an issue here on behalf of @stendler.

The issue needs the following to reproduce:

  • An (abstract?) base aspect in annotation-based @AspectJ syntax, containing an if() pointcut like this:

    @Pointcut("if()")
    public static boolean isEnabled() {
      return true;
    }
  • An aspect extending the base aspect

  • A compiler step 1 compiling the base aspect separately.

  • A compiler step 2 compiling the extending aspect + an optional demo application.

This will yield an AJC error as follows (line breaks added for better readability):

com\example\AbstractAspectWithStatic.aj [error]
  can't override pointcut com.example.AbstractAspectWithStatic.isEnabled()
  with pointcut com.example.AbstractAspectWithStatic.isEnabled()
  return types don't match

Noteworthy:

  • Interestingly, when running the demo application after the failed compilation step 2, the aspect (at least my simple example one) seems to be applied and to work normally.

  • The same scenario with a native base aspect works as expected without any compiler or runtime errors. Whether the extending aspect is in native or annotation syntax, does not seem to be so important.

  • In both the native and annotation syntax scenarios, when compiling both aspects together without any binary weaving step, there are no problems.

How to reproduce

Example code

We need at least those two classes:

package com.example;

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

@Aspect
public abstract class AbstractAspectWithStatic {
  @Pointcut("if()")
  public static boolean isEnabled() {
    return true;
  }

  @Pointcut
  public abstract void pointCut();

  @Around("isEnabled() && pointCut()")
  public Object myAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
    System.out.println("AbstractAspectWithStatic: " + joinPoint);
    return joinPoint.proceed();
  }
}
package com.example;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class InheritingAspect extends AbstractAspectWithStatic {
  @Pointcut("execution(* com.example.Application.*(..))")
  public void pointCut() {}
}

If we want to run the compiled code, we also need this demo application:

package com.example;

public class Application {
  public static void main(String[] args) {
    System.out.println("Hello, World!");
    doSomething();
  }

  public static void doSomething() {
    System.out.println("Doing something...");
  }
}

For a negative or regression test, here are two native syntax aspects:

package com.example;

public abstract aspect AbstractNativeAspectWithStatic {
  pointcut isEnabled(): if(true);

  abstract pointcut pointCut();

  Object around(): isEnabled() && pointCut() {
    System.out.println("AbstractNativeAspectWithStatic: " + thisJoinPoint);
    return proceed();
  }
}
package com.example;

public aspect InheritingNativeAspect extends AbstractNativeAspectWithStatic {
  pointcut pointCut(): execution(* com.example.Application.*(..));
}

Compiling and running the application

Reproducing the compiler error

Here, we see the compiler error in step 2 and the application running fine despite that error.

$ ajc -8 -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar" src/main/java/com/example/AbstractAspectWithStatic.aj

$ ajc -8 -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar;src/main/java" src/main/java/com/example/InheritingAspect.aj src/main/java/com/example/Application.java
com\example\AbstractAspectWithStatic.aj [error] can't override pointcut com.example.AbstractAspectWithStatic.isEnabled() with pointcut com.example.AbstractAspectWithStatic.isEnabled() return types don't match


1 error

$ java -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar;src/main/java" com.example.Application
AbstractAspectWithStatic: execution(void com.example.Application.main(String[]))
Hello, World!
AbstractAspectWithStatic: execution(void com.example.Application.doSomething())
Doing something...

Negative/regression test

No problems with native syntax aspects.

$ ajc -8 -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar" src/main/java/com/example/AbstractNativeAspectWithStatic.aj

$ ajc -8 -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar;src/main/java" src/main/java/com/example/InheritingNativeAspect.aj src/main/java/com/example/Application.java

$ java -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar;src/main/java" com.example.Application
AbstractNativeAspectWithStatic: execution(void com.example.Application.main(String[]))
Hello, World!
AbstractNativeAspectWithStatic: execution(void com.example.Application.doSomething())
Doing something...

Single-stage compilation

If everything is compiled together, it works as expected.

$ ajc -8 -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar" src/main/java/com/example/AbstractAspectWithStatic.aj src/main/java/com/example/AbstractNativeAspectWithStatic.aj src/main/java/com/example/InheritingAspect.aj src/main/java/com/example/InheritingNativeAspect.aj src/main/java/com/example/Application.java 

$ java -cp "c:/Program Files/Java/AspectJ/lib/aspectjrt.jar;src/main/java" com.example.Application
AbstractNativeAspectWithStatic: execution(void com.example.Application.main(String[]))
AbstractAspectWithStatic: execution(void com.example.Application.main(String[]))
Hello, World!
AbstractNativeAspectWithStatic: execution(void com.example.Application.doSomething())
AbstractAspectWithStatic: execution(void com.example.Application.doSomething())
Doing something...

AspectJ Maven reproducer

Using this POM and a standard Maven directory layout, the problem can also be reproduced easily:

<?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>AJ_MH_AJMaven_GH-222</artifactId>
  <version>1.0-SNAPSHOT</version>

  <properties>
    <maven.compiler.release>8</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <aspectj.version>1.9.24</aspectj.version>
  </properties>

  <build>
    <plugins>

      <plugin>
        <!-- Deactivate Maven Compiler to avoid any possible side effects on AJ Maven -->
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.13.0</version>
        <executions>
          <execution>
            <id>default-compile</id>
            <phase>none</phase>
          </execution>
          <execution>
            <id>default-testCompile</id>
            <phase>none</phase>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <groupId>dev.aspectj</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.14.1</version>
        <configuration>
          <complianceLevel>${maven.compiler.release}</complianceLevel>
        </configuration>
        <executions>
          <execution>
            <!-- In stage 1, compile abstract aspect with static 'if()' pointcut method -->
            <id>stage-1</id>
            <goals>
              <goal>compile</goal>
            </goals>
            <configuration>
              <includes>
                <include>**/Abstract*</include>
                <include>**/Application*</include>
              </includes>
            </configuration>
          </execution>
          <execution>
            <!-- In stage 2, extend previously compiled abstract aspect with static 'if()' pointcut method -->
            <id>stage-2</id>
            <goals>
              <goal>compile</goal>
            </goals>
            <configuration>
              <includes>
                <include>**/Inheriting*</include>
              </includes>
            </configuration>
          </execution>
        </executions>

        <dependencies>
          <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>${aspectj.version}</version>
          </dependency>
        </dependencies>
      </plugin>

    </plugins>
  </build>

  <dependencies>
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjrt</artifactId>
      <version>${aspectj.version}</version>
    </dependency>
  </dependencies>

</project>

Console log:

$ mvn clean compile

(...)
[INFO] ----------------< de.scrum-master:AJ_MH_AJMaven_GH-222 >----------------
[INFO] Building AJ_MH_AJMaven_GH-222 1.0-SNAPSHOT
[INFO]   from pom.xml
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] 
[INFO] --- clean:3.2.0:clean (default-clean) @ AJ_MH_AJMaven_GH-222 ---
[INFO] 
[INFO] --- resources:3.3.1:resources (default-resources) @ AJ_MH_AJMaven_GH-222 ---
[INFO] Copying 0 resource from src\main\resources to target\classes
[INFO] 
[INFO] --- aspectj:1.14.1:compile (stage-1) @ AJ_MH_AJMaven_GH-222 ---
[INFO] Showing AJC message detail for messages of types: [error, warning, fail]
[ERROR] unrecognized single argument: "C:\Users\alexa\Documents\java-src\AJ_MH_AJMaven_GH-222\src\main\java\com\example\AbstractAspectWithStatic.class"
	<unknown source file>:<no line information>

[ERROR] no sources specified
	<unknown source file>:<no line information>

[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions