如何使用aspectj围绕aspect修改未知数量的方法args

问题描述

我想创建一个注释,该注释使用一个around方面来清理带有该注释的参数。

例如,一种方法可能类似于:

public void setName(@Scrubbed String name) { ... }

或者也许

public void setFullName(@Scrubbed String firstName,@Scrubbed String lastName) { ... }

我想做的就是这些事情:

Object around(String arg) : call(* *(..,@Scrubbed (String),..)) {
    return proceed(this.scrubString(arg));
}

但是,我想以任何顺序处理任意数量的参数。 我正在工作的东西,但似乎是个hack:

Object around() : call(public * *(..,..)) {
    Method method = MethodSignature.class.cast(thisJoinPoint.getSignature()).getmethod();
    Object[] args = thisJoinPoint.getArgs();
    Annotation[][] parameterannotations = method.getParameterannotations();
    for (int argIndex = 0; argIndex < args.length; argIndex++) {
        for (Annotation paramAnnotation : parameterannotations[argIndex]) {
            if (!(paramAnnotation instanceof Scrubbed)) {
                continue;
            }
            args[argIndex] = this.scrubString((String)args[argIndex]);
        }
    }
    try {
        return method.invoke(thisJoinPoint.getTarget(),args);
    } catch (illegalaccessexception | IllegalArgumentException | InvocationTargetException e) {
        e.printstacktrace();
    }
    return null;
}

我基本上是使用joinPoint来访问反射信息,并最终使用method.invoke而不是proceed()。

我希望能够访问ProceedingJoinPoint并调用它提供的proceed(Ojbect [] args)方法,但是我不知道如何使用本机AspectJ语法来做到这一点。

任何想法。我以为我可以使用注释@AJ Aspectj语法,但其余各方面都使用本机语法。

解决方法

非常抱歉,我无法为您提供本机AspectJ语法的优雅解决方案,因为与基于注释的语法相比,我更喜欢它。但这是罕见的情况之一,在这种情况下,您想要使用@AspectJ语法更轻松地实现目标。

关于在任意位置和数字上的参数注释,您需要按照已经建议的方式使用反射。这种方法签名的不确定性无法通过常规切入点和参数绑定语法来解决。

但是使用@AspectJ语法确实可以进行getArgs()参数数组的修改版本。我们开始:

标记注释:

package de.scrum_master.app;

import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention(RUNTIME)
@Target(PARAMETER)
public @interface Scrubbed {}

目标类别+驱动程序应用程序

package de.scrum_master.app;

public class Application {
  public void setName(@Scrubbed String name) {
    System.out.println("name = " + name);
  }

  public void setFullName(@Scrubbed String firstName,@Scrubbed String lastName) {
    System.out.println("firstName = " + firstName + ",lastName = " + lastName);
  }

  public static void main(String[] args) {
    Application application = new Application();
    application.setName("Albert Einstein");
    application.setFullName("Albert","Einstein");
  }
}

方面:

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

import de.scrum_master.app.Scrubbed;

@Aspect
public class StringScrubberAspect {
  @Around("call(public * *(..,@de.scrum_master.app.Scrubbed (String),..))")
  public Object scrubStringAdvice(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    Method method = MethodSignature.class.cast(thisJoinPoint.getSignature()).getMethod();
    Object[] args = thisJoinPoint.getArgs();
    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    for (int argIndex = 0; argIndex < args.length; argIndex++) {
      for (Annotation paramAnnotation : parameterAnnotations[argIndex]) {
        if (paramAnnotation instanceof Scrubbed)
          args[argIndex] = scrubString((String) args[argIndex]);
      }
    }
    return thisJoinPoint.proceed(args);
  }

  private String scrubString(String string) {
    return string.replaceAll("[Ee]","#");
  }
}

控制台日志:

name = Alb#rt #inst#in
firstName = Alb#rt,lastName = #inst#in

更新:我刚刚看到您已经建议了这种方法:

我以为我可以使用注解@AJ Aspectj语法,但其余各方面都使用本机语法。

这可能是表面上的缺陷,但是没有理由不能混合使用两种语法类型,只要您不在同一方面混合使用它们即可。 (即使后者在很多情况下都有效,但在某些情况下却无效。)