Thanks for all the friends here. I know how to get the annotation parameter for the annotation set on method
.
While I would like to add the annotation in the Class
level. How to retrieve the attribute from Class
in the AOP Around method?
By the way, I have another question, why I need to change the response value from void
to Object
and return pjp.proceed()
. If the method do not have response, the request will freezing.
For the Method which has HasRole annotation
@Around("@annotation(com.example.demo.aspect.annotation.HasRole) && @annotation(annotation)")
public void aroundHasRole(ProceedingJoinPoint pjp, HasRole annotation) throws Throwable {
log.info("value->>{}", annotation.value());
pjp.proceed();
}
For Class or Method which has HasRole annotation
@Around("(@within(com.example.demo.aspect.annotation.IsAdmin)"
+ "|| @annotation(com.example.demo.aspect.annotation.IsAdmin))")
public Object aroundHasRole(ProceedingJoinPoint pjp) throws Throwable {
<<How to get annotation information here?>>
return pjp.proceed();
}
As you probably have noticed, you cannot bind information from different ||
branches to an advice method parameter because it would be ambiguous, see also my answers here and here. So if you want to avoid ugly (and slow) reflection, do what I recommended in the other answers and write two distinct advices, factoring out the common code into a helper method if avoiding code duplication is your concern here. Something like this (untested, just to give you an idea about the code structure):
@Around("@within(annotation)")
public Object classIsAdmin(ProceedingJoinPoint pjp, IsAdmin annotation) throws Throwable {
return commonIsAdmin(pjp, annotation);
}
@Around("@annotation(annotation)")
public Object methodIsAdmin(ProceedingJoinPoint pjp, IsAdmin annotation) throws Throwable {
return commonIsAdmin(pjp, annotation);
}
public Object commonIsAdmin(ProceedingJoinPoint pjp, IsAdmin annotation) throws Throwable {
// Here you would place all common advice code.
// Non-common code could remain in the original advice methods.
log.info("value->>{}", annotation.value());
return pjp.proceed();
}
why I need to change the response value from
void
toObject
and returnpjp.proceed()
. If the method do not have response, the request will freezing.
In contrast to a @Before
or @After
advice, in an @Around
advice you can modify the return value by either skipping the target method execution completely by not calling proceed()
or by discarding or modifying the result of proceed()
. You are completely free in what you want to return, it just has to match the target method's return type.
Having said that, it should become clear that an around advice method also must have a return type matching that of the target method(s) it intercepts. It can be an exact type like MyType
, a super type or simply Object
(super type for all types) if your advice targets a multitude of types without a common super type. The advice can also have a return type of void
if (and only if) all target methods also return void
(otherwise the advice just would not match those methods, even if the pointcut as such would match).
So if an around advice matches is determined by a combination of the pointcut itself and the return type. You can use that as a tool to limit pointcut matching by defining a specific return type (to which you then would need to cast the return value of proceed()
because proceed()
always returns an Object
).
BTW, if the target method returns a primitive type like int
, boolean
etc., then the advice would auto-wrap the result to be an Integer
or Boolean
.
You really ought to read Spring AOP and AspectJ manuals or tutorials because I am explaining things here which can be found there.
Update: The OP asked for documentation concerning parameter binding and a description how names are determined:
argNames
parameter for all advice types, e.g. @Before
, @After
, @Around
.All of this is described in the Spring AOP manual.