使用 Aspectj 调用 joinPoint.getArgs 时如何忽略带有 javax 注释的参数? [英] How to ignore parameters with javax annotation when calling joinPoint.getArgs using Aspectj?

查看:40
本文介绍了使用 Aspectj 调用 joinPoint.getArgs 时如何忽略带有 javax 注释的参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的函数包含不同的 javax 查询注释,例如:@QueryParam@Context@PathParam 等.

I have functions that include different javax Query annotations like : @QueryParam , @Context , @PathParam etc..

有没有办法在调用joinPoint.getArgs()时排除这些参数?

is there a way to exclude these parameters when calling joinPoint.getArgs()?

示例:

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    @Path("{pathParam}/v1/{pathParam2}/")
    @MyAnnotation
    public Response update(@PathParam("pathParam") String p1, @PathParam("pathParam2") int p2, MyObject x);



    @Before("@annotation(MyAnnotation)")
        public void doSomething(JoinPoint joinPoint){
            Object[] objects = joinPoint.getArgs(); // HERE - is there a way to get only MyObject and not other params..?
    }

我想这样做的原因是我有几个 url,同时将 ~10% 标记为持久性.这意味着我希望将输入数据保存在某个持久服务中.查询&上下文参数对我来说并不重要,但输入数据本身很重要.

The reason I want to do it is that I have several urls, while marking ~10% as persistent. It means that I want the input data to be saved in some persistent service. The Query & Context params are not important to me, but the input data itself is.

推荐答案

假设您真的像许多其他人一样使用 full AspectJ 而不是 Spring AOP,您应该意识到在 full AspectJ 中@annotation(XY) 不仅可能匹配 execution() 连接点,还可能匹配 call(),即您的建议将被触发两次.更糟糕的是,如果方法执行以外的其他地方也被注释了 - 例如类、字段、构造函数、参数 - 切入点也将匹配,并且您尝试强制转换为 MethodSignature 将导致异常结果.

Assuming you really use full AspectJ and not Spring AOP like so many others, you should be aware of the fact that in full AspectJ @annotation(XY) potentially matches not just execution() joinpoints but also call(), i.e. your advice will be triggered twice. Even worse, if other places than method executions are also annotated - e.g. classes, fields, constructors, parameters - the pointcut will also match and your try to cast to MethodSignature will cause an exception as a consequence.

此外,请注意,在@AspectJ 语法中,您需要提供要与之匹配的注解的完全限定类名,即不要忘记还要加上包名.否则根本就没有匹配.因此,在做任何其他事情之前,您想将切入点更改为:

Furthermore, please note that in @AspectJ syntax you need to provide the fully qualified class name of the annotation you want to match against, i.e. don't forget to also prepend the package name. Otherwise there will be no match at all. So before doing anything else you want to change your pointcut to:

@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))

现在这是一个完全自洽的例子,一个 SSCCE 产生可重复的结果,正如我在在您的问题下发表评论:

Now here is a fully self-consistent example, an SSCCE producing repeatable results, as requested by me in the comment under your question:

注释:

package de.scrum_master.app;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {}

驱动程序应用:

如您所见,测试方法具有带有不同类型注释的参数:

As you can see, the test method has parameters with different types of annotations:

  1. 只有javax注解
  2. javax + 自己的注解
  3. 只有您自己的注释
  4. 无注释

我们想忽略#1/2,只打印#3/4.

We want to ignore #1/2 and only print #3/4.

package de.scrum_master.app;

import javax.ws.rs.PathParam;
import javax.ws.rs.core.Response;

public class Application {
  public static void main(String[] args) {
    new Application().update("foo", 11, "bar", 22);
  }

  @MyAnnotation
  public Response update(
    @PathParam("pathParam") String p1,
    @PathParam("pathParam2") @MyAnnotation int p2,
    @MyAnnotation String text,
    int number
  ) {
    return null;
  }
}

方面:

正如用户 Andre Paschoal 在他的代码片段中开始展示的那样,您需要迭代参数和注释数组以实现过滤技巧.我认为这很丑陋,并且可能只是为了记录而速度很慢(我认为这就是您想要做的),但就其价值而言,这是您的解决方案:

Just as user Andre Paschoal started to show in his code fragment, you need to iterate over both the arguments and annotations arrays in order to pull off the filtering trick. I think it is quite ugly and possibly slow just for logging's sake (and I assume this is what you want to do), but for what it is worth, here is your solution:

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect
public class ParameterFilterAspect {
  @Before("@annotation(de.scrum_master.app.MyAnnotation) && execution(* *(..))")
  public void doSomething(JoinPoint joinPoint) {
    Object[] args = joinPoint.getArgs();
    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Annotation[][] annotationMatrix = methodSignature.getMethod().getParameterAnnotations();
    for (int i = 0; i < args.length; i++) {
      boolean hasJavaxAnnotation = false;
      for (Annotation annotation : annotationMatrix[i]) {
        if (annotation.annotationType().getPackage().getName().startsWith("javax.")) {
          hasJavaxAnnotation = true;
          break;
        }
      }
      if (!hasJavaxAnnotation)
        System.out.println(args[i]);
    }
  }
}

控制台日志:

bar
22

多啊!:-)

这篇关于使用 Aspectj 调用 joinPoint.getArgs 时如何忽略带有 javax 注释的参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆