Search code examples
javaspringspring-aop

Modify value from class with @AfterReturning in Spring AOP


How to modify value with @AfterReturning advice, it works for any object except String. I know that String is Immutability. and how to modify the string without changing returning type of saveEverything() function in AccountDAO class? here are code snippet:

@Component
public class AccountDAO {
    public String saveEverything(){
        String save = "save";
        return save;
    }
}

and aspect:

@Aspect
@Component
public class AfterAdviceAspect {
    @AfterReturning(pointcut = "execution(* *.save*())", returning = "save")
    public void afterReturn(JoinPoint joinPoint, Object save){
        save = "0";
        System.out.println("Done");
    }
}

and main app:

public class Application {
public static void main(String[] args) {
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(JavaConfiguration.class);

    AccountDAO accountDAO = context.getBean("accountDAO", AccountDAO.class);

    System.out.println(">"+accountDAO.saveEverything());;

    context.close();
  }
}

Solution

  • From the documentation :After Returning Advice

    Please note that it is not possible to return a totally different reference when using after returning advice.

    As anavaras lamurep rightly pointed out in the comments , @Around advice can be used to achieve your requirement. An example aspect would be as follows

    @Aspect
    @Component
    public class ExampleAspect {
        @Around("execution(* com.package..*.save*()) && within(com.package..*)")
        public String around(ProceedingJoinPoint pjp) throws Throwable {
            String rtnValue = null;
            try {
                // get the return value;
                rtnValue = (String) pjp.proceed();
            } catch(Exception e) {
                // log or re-throw the exception 
            }
            // modify the return value
            rtnValue = "0";
            return rtnValue;
        }
    }
    

    Please note that the pointcut expression given in the question is global . This expression will match call to any spring bean method starting with save and returning an Object. This might have undesired outcome. It is recommended to limit the scope of classes to advice.

    --- Update ---

    As pointed out by @kriegaex , for better readability and maintainability the pointcut expression may be rewritten as either

    execution(* com.package..*.save*())
    

    or

    execution(* save*()) && within(com.package..*)