1. Introduction

In this post, I would demo how to solve error Type referred to is not an annotation type when using Spring AOP.

2. Environment

  • SpringBoot 2
  • java 1.8+
  • AspectJ Tools 1.9.4

3. The POM

We only use the SpringBoot 2 and AspectJ 1.9.4 , the POM is as follows:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjtools</artifactId>
        <version>1.9.4</version>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <!-- Import dependency management from Spring Boot -->
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.0.2.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

4. The Code

We want to use Spring AOP to add logging ability to SpringBoot web controllers, the code is as follows:

The Controller:

package com.bswen.testspringaop.controllers;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
    @RequestMapping(value = "hello")
    public @ResponseBody String getHello() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello";
    }
}

You can see that, this controller just simply returns a string, the url is http://localhost:8080/hello

The Spring AOP Aspect:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MyConrollerLogger {
    private static Logger logger = LoggerFactory.getLogger(MyConrollerLogger.class);

    @Around("@within(com.bswen.testspringaop.controllers.HelloController)") // we want HelloController to be instrumented
    public void logAround(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.nanoTime();
        Object retval = pjp.proceed();
        long end = System.nanoTime();
        String methodName = pjp.getSignature().getName();
        logger.info("Execution of " + methodName + " took " +
                TimeUnit.NANOSECONDS.toMillis(end - start) + " ms");
    }
}

Run the code, we got the error message:

2019-07-06 22:54:40.012  WARN 22494 --- [           main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat': Initialization of bean failed; nested exception is **java.lang.IllegalArgumentException: error Type referred to is not an annotation type: com.bswen.testspringaop.controllers.HelloController**
2019-07-06 22:54:40.024  INFO 22494 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-07-06 22:54:40.039 ERROR 22494 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat': Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error Type referred to is not an annotation type: com.bswen.testspringaop.controllers.HelloController
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:155) ~[spring-boot-2.0.2.RELEASE.jar:2.0.2.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:544) ~[spring-context-5.0.6.RELEASE.jar:5.0.6.RELEASE]

5.Why did this error happen?

we had this error because we misused the Within expression,according to spring aop documents, When we define the pointcut by using within, there are following usages examples:

  • any join point (method execution only in Spring AOP) within the service package:
    • within(com.xyz.service.*)
  • any join point (method execution only in Spring AOP) within the service package or a sub-package:
    • within(com.xyz.service..*)
  • any join point (method execution only in Spring AOP) where the declared type of the target object has an @Transactional annotation:
    • @within(org.springframework.transaction.annotation.Transactional)

Here we used the Within like this:

  • @Around(“within(@com.bswen.testspringaop.controllers.HelloController *)”)

It would let spring to find the class with annotation @HelloController, and because no class is annoatated by it, so there is an error.

6.How to solve this problem?

We should change the pointcut expression to this:

@Around("within(com.bswen.testspringaop.controllers.*)")

This means any class under com.bswen.testspringaop.controllers package should be instrumented.

Run the code, we get this:

2019-07-06 23:29:09.443  INFO 22579 --- [nio-8080-exec-1] c.b.t.aspects.MyConrollerLogger          : Execution of getHello took 1007 ms

6. Summary

Be careful if you want to use Within in spring aop pointcut expressions.