springboot-How to solve error Type referred to is not an annotation type exception?
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.