I have read the following valuable links:
Consider this request for a setter method
public void setSomething(@ParameterLevel(name="abc") String something){
this.something = something;
}
I have the following and works fine:
@Pointcut("execution(* *.*(@somepackage.ParameterLevel (*)))")
void parameterLevel01() {}
Now I want retrieve the @ParameterLevel
annotation through a method's parameter such as the following:
@Pointcut("execution(* *.*(@somepackage.ParameterLevel (*)))")
void parameterLevel01(ParameterLevel parameterLevel) {} <--To be used directly in the advice method
The purpose is use the Annotation directly how a parameter in the advice method
Something similar such as:
@within(classLevel)
for @ClassLevel
in:
@ClassLevel
public class SomeClass {
...
}
@annotation(methodLevel)
for @MethodLevel
in:
@MethodLevel
public void somethingToDo(){
...
}
How accomplish this goal. Is possible? I am working with AspectJ 1.9.6
No matter if you use .., @MyAnnotation (*), ..
or just @MyAnnotation (*)
, which only removes the ambiguity of possibly multiple matches, there is no direct way to bind a method argument annotation to an advice argument, only the method argument itself. This has not changed in AspectJ. You would have seen it mentioned in the release notes otherwise, because it would be a new feature.
So you will have to use the method from my other two answers which you have already linked to in your question, i.e. iterating over parameter types and annotations manually.
Somewhat off-topic, there is a very old Bugzilla ticket #233718 which is about binding multiple matched (annotated) parameters, but not about binding their annotations. It came up in a recent discussion I had with AspectJ maintainer Andy Clement. But even if this was implemented one day, it would not solve your problem.
I think you can take it from here and adapt my solution from the linked questions to your needs. Feel free to let me know if you have any follow-up questions about that, but it should be pretty straightforward. You might be able to optimise because you know the exact parameter position (think array index), if you feel so inclined, i.e. you don't need to iterate over all parameters.
Update: Here is a little MCVE for you. It is based on this answer and has been simplified to assume the annotation is always on the first parameter and the first parameter only.
Please learn what an MCVE is and provide one by yourself next time because it is your job, not mine. This was your free shot.
Marker annotation + driver application:
package de.scrum_master.app;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
@Retention(RUNTIME)
public @interface ParameterLevel {
String name();
}
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
new Application().doSomething("foo");
}
public void doSomething(@ParameterLevel(name="abc") String string) {}
}
Aspect:
package de.scrum_master.aspect;
import java.lang.annotation.Annotation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.SoftException;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import de.scrum_master.app.ParameterLevel;
@Aspect
public class ParameterLevelAspect {
@Before("execution(public * *(@de.scrum_master.app.ParameterLevel (*))) && args(string)")
public void beforeAdvice(JoinPoint thisJoinPoint, String string) {
System.out.println(thisJoinPoint + " -> " + string);
MethodSignature signature = (MethodSignature) thisJoinPoint.getSignature();
String methodName = signature.getMethod().getName();
Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
Annotation[] annotations;
try {
annotations = thisJoinPoint.getTarget().getClass()
.getMethod(methodName, parameterTypes)
.getParameterAnnotations()[0];
} catch (NoSuchMethodException | SecurityException e) {
throw new SoftException(e);
}
ParameterLevel parameterLevel = null;
for (Annotation annotation : annotations) {
if (annotation.annotationType() == ParameterLevel.class) {
parameterLevel = (ParameterLevel) annotation;
break;
}
}
assert parameterLevel != null;
System.out.println(" " + parameterLevel + " -> " + parameterLevel.name());
}
}
Console log:
execution(void de.scrum_master.app.Application.doSomething(String)) -> foo
@de.scrum_master.app.ParameterLevel(name="abc") -> abc