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

AspectJ: Pointcut to declare and retrieve an annotation of a method's parameter

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

考虑此请求 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

目的是直接使用Annotation如何在advice方法中作为参数

类似的内容,例如:

@within(classLevel) 对于 @ClassLevel 在:

@ClassLevel
public class SomeClass {
  ...
}

@annotation(methodLevel) 对于 @MethodLevel 在:

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

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

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

所以你将不得不使用你已经在你的问题中链接到的我的其他两个答案中的方法,即手动迭代参数类型和注释。

有点 off-topic,我和 AspectJ 维护者 Andy Clement 有一个非常古老的 Bugzilla ticket #233718 which is about binding multiple matched (annotated) parameters, but not about binding their annotations. It came up in a recent discussion。但即使有一天实现了,也解决不了你的问题。

我想你可以从这里开始,根据你的需要根据链接的问题调整我的解决方案。如果您对此有任何 follow-up 问题,请随时告诉我,但这应该非常简单明了。您可能能够进行优化,因为您知道确切的参数位置(想想数组索引),如果您愿意的话,即您不需要遍历所有参数。


更新:这里有一点MCVE for you. It is based on 并且已经简化为假设注释总是在第一个参数上并且只在第一个参数上。

请了解什么是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