eclipse-aspectj / aspectj

Other
335 stars 87 forks source link

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

Open kriegaex opened 3 weeks ago

kriegaex commented 3 weeks ago

Preface

Originally reported as https://github.com/mojohaus/aspectj-maven-plugin/issues/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:

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:

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] ------------------------------------------------------------------------
kriegaex commented 3 weeks ago

You can avoid copy & paste for the reproducer by cloning this: https://github.com/kriegaex/AJ_MH_AJMaven_GH-222