AspectJ:用于声明和检索方法参数注释的切入点



我已经阅读了以下有价值的链接:

  • 带注释参数的Spring AOP切入点
  • 如何基于带注释的参数编写Aspect切入点
  • AspectJ切入点表达式在任何位置匹配参数注释

考虑对setter方法的请求

public void setSomething(@ParameterLevel(name="abc") String something){
this.something = something;
}

我有以下内容并且工作良好:

@Pointcut("execution(* *.*(@somepackage.ParameterLevel (*)))")
void parameterLevel01() {}

现在,我想通过方法的参数检索@ParameterLevel注释,例如:

@Pointcut("execution(* *.*(@somepackage.ParameterLevel (*)))")
void parameterLevel01(ParameterLevel parameterLevel) {} <--To be used directly in the advice method

目的是直接使用注释如何在建议方法中使用参数

类似的东西,例如:

@ClassLevel@within(classLevel)

@ClassLevel
public class SomeClass {
...
}

@annotation(methodLevel)用于中的@MethodLevel

@MethodLevel
public void somethingToDo(){
...
}

如何实现这个目标。有可能吗?我正在使用AspectJ 1.9.6

无论您使用.., @MyAnnotation (*), ..还是仅使用@MyAnnotation (*),这只会消除可能的多个匹配的歧义,都没有直接的方法将方法参数注释绑定到建议参数,只有方法参数本身。这在AspectJ中没有改变。否则你会在发行说明中看到它,因为它将是一个新功能。

因此,您必须使用我在问题中已经链接到的另外两个答案中的方法,即手动迭代参数类型和注释。

有些偏离主题的是,有一个非常古老的Bugzilla票证#233718,它是关于绑定多个匹配(带注释(的参数,但不是关于绑定它们的注释。这是我最近与AspectJ维护人员Andy Clement进行的一次讨论中提到的。但是,即使有一天实现了这一点,它也不会解决你的问题。

我认为你可以从这里开始,根据你的需求调整我的解决方案。如果你对此有任何后续问题,请随时告诉我,但应该非常简单。如果你觉得有这种倾向,你可能能够进行优化,因为你知道确切的参数位置(想想数组索引(,也就是说,你不需要迭代所有参数。


更新:这里有一个小MCVE。它基于这个答案,并被简化为假设注释始终在第一个参数上,并且仅在第一个参数值上。

请了解什么是MCVE,下次自己提供,因为这是你的工作,而不是我的工作。这是你的罚球

标记注释+驱动程序应用程序:

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) {}
}

方面:

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());
}
}

控制台日志:

execution(void de.scrum_master.app.Application.doSomething(String)) -> foo
@de.scrum_master.app.ParameterLevel(name="abc") -> abc

最新更新