Surabhya Aryal
Surabhya Aryal

Reputation: 1

aspectj compile time weaving - ajc$perSingletonInstance is null

I aimed to implement compile-time weaving in my codebase and discovered the AspectJ Maven plugin (https://dev-aspectj.github.io/aspectj-maven-plugin/).

aspectj.version = 1.9.21
maven-compiler.version = 3.11.0
java.version = 21

I made the following modifications:

Added the following code under the dependencies section:

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

Included the following code under the <plugins> section:

<plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven-compiler.version}</version>
    <executions>
        <execution>
            <id>default-compile</id>
            <configuration>
                <compilerArguments>
                    <d>${project.build.directory}/unwoven-classes</d>
                </compilerArguments>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>dev.aspectj</groupId>
    <artifactId>aspectj-maven-plugin</artifactId>
    <version>1.13.1</version>
    <configuration>
        <complianceLevel>${java.version}</complianceLevel>
        <showWeaveInfo>true</showWeaveInfo>
        <forceAjcCompile>true</forceAjcCompile>
        <sources/>
        <weaveDirectories>
            <weaveDirectory>${project.build.directory}/unwoven-classes</weaveDirectory>
        </weaveDirectories>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>compile</goal>
            </goals>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjtools</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
    </dependencies>
</plugin>

Due to compatibility issues between Lombok and AspectJ, I initially compile to unwoven-classes before proceeding to target/classes. Running mvn clean compile results in a successful build with [INFO] Join point.... However, during application startup, I encounter the following error:

Caused by: org.aspectj.lang.NoAspectBoundException:
  Exception while initializing com.xyz.apirest.authorization.EnsureFromMonolith:
  java.lang.NoSuchMethodError: com.xyz.apirest.authorization.EnsureFromMonolith:
  method 'void <init>()' not found
    at com.xyz.apirest.authorization.EnsureFromMonolith.aspectOf(EnsureFromMonolith.java:1)
    at com.xyz.apirest.v1.internal.workflows.InternalDisbursementController.<clinit>(InternalDisbursementController.java:1)
    ... 124 common frames omitted
Caused by: java.lang.NoSuchMethodError:
  com.xyz.apirest.authorization.EnsureFromMonolith:
  method 'void <init>()' not found
    at com.xyz.apirest.authorization.EnsureFromMonolith.ajc$postClinit(EnsureFromMonolith.java:1)
    at com.xyz.apirest.authorization.EnsureFromMonolith.<clinit>(EnsureFromMonolith.java:1)
    ... 125 common frames omitted

The relevant code snippet is as follows:

@Aspect
@Component
@RequiredArgsConstructor
public class EnsureFromMonolith {
    private final AuthenticationProfile authenticationProfile;
    private final XYZJwtAuthenticationConfig xyzJwtAuthenticationConfig;
    protected final Logger logger = LoggerFactory.getLogger(EnsureFromMonolith.class);

    @Around(value = "(execution(public * *(..)) && within(@com.xyz.apirest.authorization.RequireFromMonolith *)) || @annotation(com.xyz.apirest.authorization.RequireFromMonolith)")
    public Object ensureFromMonolith(ProceedingJoinPoint joinPoint) throws Throwable {
        if (authenticationProfile.getAid() == null) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        } else if (!validateProfile(authenticationProfile, xyzJwtAuthenticationConfig.getMonolithAuthorizedClientId())) {
            return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
        }

        return joinPoint.proceed();
    }

    public static boolean validateProfile(AuthenticationProfile authenticationProfile, String monolithClientId) {
        return authenticationProfile.getAid().equals(monolithClientId);
    }
}

I've tried the solutions recommended in AspectJ not working with compile time weaving and How to build aspectj project using maven? without success.

My goal is to have the application startup successfully with AspectJ functioning as intended.

Upvotes: 0

Views: 227

Answers (2)

kriegaex
kriegaex

Reputation: 67477

As Mitya said, a native aspect does not need any @Component annotation, because it will be picked up a second time by Spring AOP, not just by native AspectJ. But that is not the root cause of your problem, just a follow-up problem if you manage to solve the main one.

The real problem here is, that a native AspectJ aspect needs a default constructor, but your Lombok-created constructor takes arguments. How are you trying to instantiate the aspect with those parameters in the first place? AspectJ creates the aspect instance on your behalf automatically. If you want to set properties, you should do so manually, using setter calls on non-final fields, or in case of Spring components you can also auto-wire them into the native aspect via @Configurable.

Upvotes: 0

Mitya
Mitya

Reputation: 101

The code doesn't work due to the use of Spring's proxy-based AOP, which is enabled when using the @Component annotation together with Spring's AOP setup. This type of AOP only supports public methods of Spring beans.

Upvotes: 0

Related Questions