12

I would like to have something like this:

public void doSomething(@ReplaceFooBar String myString) {
    //...
}

ReplaceFooBar is my custom annotation which should take the value of myString and do a replaceAll of "foo" with "bar" on it before the method starts executing so that it executes with the new string value. So, if the method was invoked with the parameter "I'm at the foo." it should actually execute with "I'm at the bar."

I don't know how to make this work. I've been fiddling with this for some time now. Let's say I last ended up at this point:

@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ReplaceFooBar {
}

And...

@Aspect
public aspect ReplaceFooBarAspect {
    @Before("@annotation(ReplaceFooBar)")
    public String replaceFooBar(String value) {
        if (value == null) {
            return null;
        }
        return value.replaceAll("foo", "bar");
    }
}

What am I doing wrong?

My code isn't compiling, I'm getting errors like these.

Error:(6, 0) ajc: Duplicate annotation @Aspect
Error:(7, 0) ajc: aspects cannot have @Aspect annotation
Error:(10, 0) ajc: This advice must return void
Error:(10, 0) ajc: formal unbound in pointcut

I don't know how these aspects work exactly, how to get this working the way I want it.

morgoth84
  • 1,070
  • 2
  • 11
  • 25
  • Well... It doesn't even compile. I thought that was obvious to someone who knows how to help me. Here are the errors: `Error:(6, 0) ajc: Duplicate annotation @Aspect Error:(7, 0) ajc: aspects cannot have @Aspect annotation Error:(10, 0) ajc: This advice must return void Error:(10, 0) ajc: formal unbound in pointcut` – morgoth84 Aug 14 '17 at 13:15
  • I really don't know why this would be important. For anyone who knows these aspects it should be perfectly clear that it doesn't compile. By adding it I'm just cluttering up my question with unnecessary data. But ok, if it will make you happy. – morgoth84 Aug 14 '17 at 13:19
  • Well, I would really love to give you verifiable code if I knew how to write it. I've spent several hours trying to make it work today without success. So I thought maybe someone here knows the answer and it will be obvious for him/her immediately, especially since the example is very simple, at last from my perspective. So instead of me spending more hours on it someone could directly help me with 5 minutes of his time. Unfortunately I don't have days to go through AspectJ tutorials right now and learn all the details myself. – morgoth84 Aug 14 '17 at 13:31

1 Answers1

12

To execute method with different argument you should use @Around advice and replace arguments manually in code.

For example:

@Around("execution(* *(.., @aspectjtest.ReplaceFooBar (*), ..))")
public Object replaceFooBar(ProceedingJoinPoint pjp) throws Throwable {
    //get original args
    Object[] args = pjp.getArgs();

    //get all annotations for arguments
    MethodSignature signature = (MethodSignature) pjp.getSignature();
    String methodName = signature.getMethod().getName();
    Class<?>[] parameterTypes = signature.getMethod().getParameterTypes();
    Annotation[][] annotations;
    try {
        annotations = pjp.getTarget().getClass().
                getMethod(methodName, parameterTypes).getParameterAnnotations();
    } catch (Exception e) {
        throw new SoftException(e);
    }

    //Find annotated argument
    for (int i = 0; i < args.length; i++) {
        for (Annotation annotation : annotations[i]) {
            if (annotation.annotationType() == ReplaceFooBar.class) {
                Object raw = args[i];
                if (raw instanceof String) {
                    // and replace it with a new value
                    args[i] = ((String) raw).replaceAll("foo", "bar");
                }
            }
        }
    }
    //execute original method with new args
    return pjp.proceed(args);
}
Vlad Bochenin
  • 3,007
  • 1
  • 20
  • 33
  • is it possible to change the data type of arguments? Like for example we accept string and then change its data type to int? Will the method still accepts it? – jawsh Feb 15 '21 at 06:41
  • 1
    I suppose you will get NoSuchMethodError than because argument's type is part of method signature. – Vlad Bochenin Feb 15 '21 at 10:55