简体   繁体   English

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

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

I have read the following valuable links:我已阅读以下有价值的链接:

Consider this request for a setter method考虑这个对 setter 方法的请求

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:现在我想通过方法的参数检索@ParameterLevel注释,例如:

@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目的是直接使用 Annotation 如何在通知方法中使用一个参数

Something similar such as:类似的东西,例如:

@within(classLevel) for @ClassLevel in: @within(classLevel)@ClassLevel在:

@ClassLevel
public class SomeClass {
  ...
}

@annotation(methodLevel) for @MethodLevel in: @annotation(methodLevel)@MethodLevel中:

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

How accomplish this goal.如何实现这个目标。 Is possible?有可能吗? I am working with AspectJ 1.9.6我正在使用 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.无论您使用.., @MyAnnotation (*), ..还是只是@MyAnnotation (*) ,它只会消除可能多个匹配的歧义,都没有直接的方法将方法参数注释绑定到建议参数,只有方法参数本身。 This has not changed in AspectJ.这在 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, ie 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.有点偏离主题,有一个非常古老的Bugzilla 票 #233718 ,它是关于绑定多个匹配(带注释)的参数,但不是关于绑定它们的注释。 It came up in a recent discussion I had with AspectJ maintainer Andy Clement.它出现在我最近与 AspectJ 维护者 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, ie you don't need to iterate over all parameters.您可能能够进行优化,因为您知道确切的参数位置(想想数组索引),如果您有这种倾向,即您不需要迭代所有参数。


Update: Here is a little MCVE for you.更新:这是给你的一个小MCVE 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.请了解什么是 MCVE,下次自己提供一个,因为这是你的工作,而不是我的。 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM