I am just facing interesting issue when I want to create an aspect for annotation like @Transactional
.
Here is the controller and annotation:
@RestController
@SimpleAnnotation
public class HelloController{
private static final Logger LOGGER = LoggerFactory.getLogger(HelloController.class);
@GetMapping("/hello")
@SimpleAnnotation(isAllowed=true)
public String helloController(){
final String methodName = "helloController";
callAnotherMerhod();
LOGGER.info("HelloController for method : {}", methodName);
return "Hello";
}
private void callAnotherMethod(){
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface SimpleAnnotation {
boolean isAllowed() default false;
}
Aspect for that annotation is here:
@Aspect
@Component
public class SimpleAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(SimpleAspect.class);
@Around(value = "@within(simpleAnnotation) || @annotation(simpleAnnotation)", argNames = "simpleAnnotation")
public Object simpleAnnotation(ProceedingJoinPoint proceedingJoinPoint, SimpleAnnotation simpleAnnotation) throws Throwable{
LOGGER.info("Simple annotation value: {}, ASPECT-LOG {}", simpleAnnotation.isAllowed(),proceedingJoinPoint.getSignature().getName());
return proceedingJoinPoint.proceed();
}
}
When I run the application and hit the http://localhost:8080/hello , everything is fine:
2020-11-09 11:36:48.230 INFO 8479 --- [nio-8080-exec-1] c.s.springaop.aspects.SimpleAspect : Simple annotation value: true, ASPECT-LOG helloController
2020-11-09 11:36:48.246 INFO 8479 --- [nio-8080-exec-1] c.s.s.controller.HelloController : HelloController for method : helloController
However if I removed annotation on the method:
@GetMapping("/hello")
public String helloController(){
final String methodName = "helloController";
callAnotherMethod();
LOGGER.info("HelloController for method : {}", methodName);
return "Hello";
}
Then simpleAnnotation
parameter becomes null, and aspect method throws NullPointerException.
After that, I changed the order of the aspect like the below, it start to work:
@Around(value = " @annotation(simpleAnnotation) || @within(simpleAnnotation)", argNames = "simpleAnnotation")
However, in this situation if I remove annotation on class level and just put only the method level, then i am facing the same NPE.
I think, in some way aspect's conditions overwrites the values.
I tried to separate the class level annotation advice and method level advice, but in that case if i have the annotation on both the class and method level, both advices work (which I do not want)
I tried to update like this:
@Around(value = "@within(simpleAnnotation) || @annotation(simpleAnnotation) || @within(simpleAnnotation)", argNames = "simpleAnnotation")
This seems to be working, but is it a good solution?
EDIT: This solution is not working also. If I have annotation both on the class and method level and let's say class level annotation value is false, and method's level is true, then annotation value will be false.