spring-bootaspectjjava-11aspectj-maven-plugin

NoSuchMethodException: com.aspectj.in.spring.boot.aop.aspect.auditlog.interceptor.LoggingInterceptorAspect.aspectOf()


I have a code that uses AspectJ. I use the compile-time weaving mode. During context initialization, I get an error. Although everything worked before that.

Here is an error in this line:

ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'getAutowireCapableLoggingInterceptor' defined in class path resource [com/aspectj/in/spring/boot/aop/aspect/auditlog/interceptor/config/LoggingInterceptorConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.aspectj.in.spring.boot.aop.aspect.auditlog.interceptor.LoggingInterceptorAspect]: Factory method 'getAutowireCapableLoggingInterceptor' threw exception; nested exception is org.aspectj.lang.NoAspectBoundException: Exception while initializing com.aspectj.in.spring.boot.aop.aspect.auditlog.interceptor.LoggingInterceptorAspect: java.lang.NoSuchMethodException: com.aspectj.in.spring.boot.aop.aspect.auditlog.interceptor.LoggingInterceptorAspect.aspectOf()

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aspectj.in.spring.boot</groupId>
    <artifactId>aspectj-in-spring-boot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>aspectj-in-spring-boot</name>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

         <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>

        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>3.0.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.3.9</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>com.nickwongdev</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.12.6</version>
                <configuration>
                    <complianceLevel>11</complianceLevel>
                    <source>11</source>
                    <target>11</target>
                    <showWeaveInfo>true</showWeaveInfo>
                    <verbose>true</verbose>
                    <Xlint>ignore</Xlint>
                    <encoding>UTF-8</encoding>
                    <aspectLibraries>
                        <aspectLibrary>
                            <groupId>org.springframework</groupId>
                            <artifactId>spring-aspects</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                    <showWeaveInfo>true</showWeaveInfo>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

enter image description here

enter image description here

enter image description here

With the help of reflection, all public methods defined in LoggingInterceptorAspect.class. But why is null returned?

Maybe someone has some ideas why initialization is not happening LoggingInterceptorAspect.class


Solution

  • Thanks for the MCVE on GitHub. Having access to it, helped me to easily identify your problems as follows:

    Your aspect should look as follows:

    package com.aspectj.in.spring.boot.aop.aspect.auditlog.interceptor;
    
    import com.aspectj.in.spring.boot.service.LoggingService;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Before;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.time.ZoneOffset;
    import java.time.ZonedDateTime;
    
    @Aspect
    public class LoggingInterceptorAspect {
        private LoggingService loggingService;
    
        @Autowired
        public void setLoggingService(LoggingService loggingService) {
            this.loggingService = loggingService;
        }
    
        @Pointcut("execution(private * *(..))")
        public void privateMethod() {}
    
        @Pointcut("execution(public * *(..))")
        public void publicMethod() {}
    
        @Pointcut("@annotation(com.aspectj.in.spring.boot.aop.aspect.auditlog.annotation.AuditAnnotation)")
        public void annotatedMethodCustom() {}
    
        @Pointcut("within(com.aspectj.in.spring.boot..*)")
        public void applicationScoped() {}
    
    
        @Before("annotatedMethodCustom() && applicationScoped()")
        //@Before("annotatedMethodCustom() && applicationScoped() && (privateMethod() || publicMethod())")
        public void addCommandDetailsToMessage(JoinPoint joinPoint) throws Throwable {
            ZonedDateTime dateTime = ZonedDateTime.now(ZoneOffset.UTC);
            String message = String.format("User controller getUsers method called at %s", dateTime);
            System.out.println("+++ " + joinPoint);
            loggingService.log(message);
        }
    }
    

    Update: I forgot to mention one possible problem in aspects which do not explicitly use execution() because they want to match all methods: When using @annotation() only, you are targetting both call() and execution() joinpoints, as you can see in the compiler log:

    [INFO] Join point 'method-call(java.util.List com.aspectj.in.spring.boot.controller.UserController.getUsersInternal())' in Type 'com.aspectj.in.spring.boot.controller.UserController' (UserController.java:26) advised by before advice from 'com.aspectj.in.spring.boot.aop.aspect.auditlog.interceptor.LoggingInterceptorAspect' (LoggingInterceptorAspect.java:37)
    [INFO] Join point 'method-execution(java.util.List com.aspectj.in.spring.boot.controller.UserController.getUsersInternal())' in Type 'com.aspectj.in.spring.boot.controller.UserController' (UserController.java:32) advised by before advice from 'com.aspectj.in.spring.boot.aop.aspect.auditlog.interceptor.LoggingInterceptorAspect' (LoggingInterceptorAspect.java:37)
    CLASSPATH component C:\Program Files\JetBrains\IntelliJ IDEA 2018.3\plugins\maven\lib\maven3\boot\plexus-classworlds.license: java.util.zip.ZipException: zip END header not found
    [INFO] Join point 'method-execution(java.util.List com.aspectj.in.spring.boot.service.impl.DefaultUserService.getMockUsers())' in Type 'com.aspectj.in.spring.boot.service.impl.DefaultUserService' (DefaultUserService.java:34) advised by around advice from 'org.springframework.cache.aspectj.AnnotationCacheAspect' (spring-aspects-5.3.9.jar!AbstractCacheAspect.class:64(from AbstractCacheAspect.aj))
    

    This also leads to duplicate runtime logging output when omitting the && (privateMethod() || publicMethod()) condition:

    +++ call(List com.aspectj.in.spring.boot.controller.UserController.getUsersInternal())
    2021-09-04 16:11:41.213  INFO 17948 --- [o-auto-1-exec-1] sample-spring-aspectj                    : User controller getUsers method called at 2021-09-04T14:11:41.210203700Z
    +++ execution(List com.aspectj.in.spring.boot.controller.UserController.getUsersInternal())
    

    In order to avoid that, you should add a generic execution pointcut:

    @Before("annotatedMethodCustom() && applicationScoped() && execution(* *(..))")