Wednesday, April 5, 2017

AspectJ: Around Advice to change value of method arguments

This is a short tutorial that explains how to write an advice to change value of method arguments.

I have implemented a MutateArgsAspect which is applied on methods annotated with @MutateArgs

The advice converts the string argument passed to the annotated method from "BEFORE" to "AFTER"

Steps 1: Implement the annotation

-------------------------------------
package com.waseem.foundation;

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

import java.lang.annotation.Retention;

@Retention(RUNTIME)
public @interface MutateArgs {


}
-------------------------------------

Steps 2: Implement the Aspect

-------------------------------------
package com.waseem.foundation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MutateArgsAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(MutateArgsAspect.class);
@Around("@annotation(MutateArgs) && execution(* *(..))")
public Object before(ProceedingJoinPoint pjp) throws Throwable {
LOGGER.debug(pjp.getSignature().toLongString());
   
Object[] args = pjp.getArgs();
   
for (int i = 0; i < args.length; i++) {
        if ("BEFORE".equals(args[i])) {
        LOGGER.info("args[{}] : {}", i, args[i]);
       
            args[i] = "AFTER";
        }
    }
    Object output = pjp.proceed(args);
return output;
}
}

Note the @Around annotation. 

1- @annotation(MutateArgs) means the Aspect is applied on all the methods annotated with MutateArgs annotation

2- execution(* *(..)) means the execution of any method regardless of return or parameter types

-------------------------------------

Step 3: Apply annotation on the methods for the Advice to work.

Here is an example where this annotation is applied on an API method

@GET
@Path("/mutateInController")
@Produces(MediaType.APPLICATION_JSON)
@MutateArgs
public Response mutateArgsOfThisMethod(@QueryParam("name")  String name) {
LOGGER.info("Name in Controller : {}", name);
return Response.ok(name).build();
}

Here is another example were this annotation is applied on another simple method

@MutateArgs
public String mutateArgsOfThisMethod(String name) {
LOGGER.info("Name in Manager : {}", name);
return name;
}