Spring AOP : pointcut @annotation (MyAnnotation) && call(.) did not fire as expected
I tried to execute a set of code in my suggestion, but couldn’t weave the code into a function with @SecuredAPI
comments and call
setQuery()
function.
I’ve tried the following entry points before and it works great
call(* org.elasticsearch.action.search.SearchRequestBuilder.setQuery(org.elasticsearch.index.query.QueryBuilder)) && args(queryBuilder)
But here you also need to include comment conditions. Please help me.
My entry point and advice are this
@Around(value = "@annotation(SecuredAPI) && call(* org.elasticsearch.action.search.SearchRequestBuilder.setQuery( org.elasticsearch.index.query.QueryBuilder)) && args(queryBuilder)" )
public Object decorateQuery(ProceedingJoinPoint proceedingJoinPoint, QueryBuilder queryBuilder) throws Throwable {
// ...
}
My function looks like this
@SecuredAPI
public List<Integer> getAllIds() {
// ...
SearchResponse response = conn
.getESClient().prepareSearch(ElasticSearchConstants.ATTRIBUTE_INDEX)
.setSearchType(SearchType.DEFAULT)
.setQuery(QueryBuilders.queryStringQuery(searchQuery))
.setQuery(qb)
.setFrom(0).setSize(10000).setExplain(true).get();
}
Please help me find a way to make it work for the following conditions
Solution
Ok, while editing your question (the code format is a bit confusing) I read it again and you said call()
actually worked for you. So you’re not using Spring AOP because call()
isn’t supported there. You must use AspectJ, either via LTW (woven on load) or CTW (woven at compile time). This has no bearing on the answer.
The problem is that @annotation(SecuredAPI
) actually works inside an execution()
entry point that is defined on your annotation method, but the method you call from there is unannotated and therefore does not trigger a suggestion for call().
It only appears when the target method setQuery(..)
is commented, but this is not the case. Therefore, @annotation()
is not the right entry point for your purposes.
What you want to say is: “Call setQuery(..)
from the code commented by @SecuredAPI
“. This is done as follows (there is no AspectJ example for Spring, adjust the class and package names to suit your needs):
package de.scrum_master.app;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target({ TYPE, FIELD, METHOD })
public @interface SecuredAPI {}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
Application application = new Application();
application.doSomething();
application.doSomethingElse();
}
@SecuredAPI
public void doSomething() {
System.out.println("Doing something before setting query");
setQuery("my first query");
System.out.println("Doing something after setting query");
}
public void doSomethingElse() {
System.out.println("Doing something else before setting query");
setQuery("my second query");
System.out.println("Doing something else after setting query");
}
public void setQuery(String query) {
System.out.println("Setting query to: " + query);
}
}
package de.scrum_master.aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class SecuredAPIAspect {
@Around("@withincode(de.scrum_master.app.SecuredAPI) && call(* setQuery(..))")
public Object myAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
System.out.println(thisJoinPoint);
return thisJoinPoint.proceed();
}
}
See? @withincode()
in this case is your friend. The console logs are as follows:
Doing something before setting query
call(void de.scrum_master.app.Application.setQuery(String))
Setting query to: my first query
Doing something after setting query
Doing something else before setting query
Setting query to: my second query
Doing something else after setting query
In addition, you need to use fully qualified class names for annotations, such as de.scrum_master.app.Secured API
, not just SecuredAPI
, unless the annotations happen to be in the same package as your aspect.