Introduction
In this post, I will demonstrate how to resolve the error “Type referred to is not an annotation type” when using Spring AOP.
Environment
SpringBoot 2
Java 1.8+
AspectJ Tools 1.9.4
The POM
We only use SpringBoot 2 and AspectJ 1.9.4. The POM is as follows:
< groupId > org.springframework.boot </ groupId >
< artifactId > spring-boot-starter-web </ artifactId >
< groupId > org.aspectj </ groupId >
< artifactId > aspectjtools </ artifactId >
<!-- Import dependency management from Spring Boot -->
< groupId > org.springframework.boot </ groupId >
< artifactId > spring-boot-dependencies </ artifactId >
< version > 2.0.2.RELEASE </ version >
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 ;
public class HelloController {
@ RequestMapping ( value = " hello " )
public @ ResponseBody String getHello () {
} catch ( InterruptedException e ) {
This controller simply returns a string, accessible at the URL 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.LoggerFactory ;
import org.springframework.stereotype.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 " ) ;
When running the code, we encounter the following error:
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]
Why did this error happen?
The error occurred because we misused the within
expression. According to the Spring AOP documentation , the within
expression is used as follows:
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)
In our case, we used the within
expression incorrectly:
@ Around ( " within(@com.bswen.testspringaop.controllers.HelloController *) " )
This caused Spring to look for a class annotated with @HelloController
, which does not exist, resulting in the error.
How to resolve this problem?
We should change the pointcut expression to:
@ Around ( " within(com.bswen.testspringaop.controllers.*) " )
This means any class under the com.bswen.testspringaop.controllers
package should be instrumented.
After making this change, running the code produces the following output:
2019-07-06 23:29:09.443 INFO 22579 --- [nio-8080-exec-1] c.b.t.aspects.MyConrollerLogger : Execution of getHello took 1007 ms
Summary
When using Spring AOP, it’s crucial to use the within
pointcut expression correctly. Misusing it can lead to errors like “Type referred to is not an annotation type.” Always ensure that the expression targets the correct package or class, and avoid using @within
unless you are targeting an annotation. By following these guidelines, you can effectively leverage Spring AOP for logging and other cross-cutting concerns.
Final Words + More Resources
My intention with this article was to help others who might be considering solving such a problem.
So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by
email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by
starring the repo on GitHub !