1

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();
  }
}

1 Answers1

5

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..*)
R.G
  • 6,436
  • 3
  • 19
  • 28
  • One way to make a small improvement to this correct answer would be to get rid of the redundant package name specifier via either just `execution(* com.package..*.save*())` or `execution(* save*()) && within(com.package..*)`. :-) – kriegaex May 13 '20 at 10:38
  • That is something I wanted to ask . I started writing point cut expressions that way after reading [this](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#writing-good-pointcuts) : *A well written pointcut should include at least the first two types (kinded and scoping)*. Please let me know if I need to convert this to a SO question so that it can benefit others ? – R.G May 13 '20 at 10:46
  • 1
    That is a general advice and as such makes sense, of course. What I don't like as a programmer is redundancy. If you refactor your package structure, in this case you would have to update the pointcut in two places - easy to forget one. Also I find the longer pointcut more difficult to read. If you look at my first example, it is both kinded and scoped. So is the second example, but both without the redundant package name. It might be a matter of personal preference, of course, but I prefer my suggested variants to yours. As I said before, yours is also correct. I will upvote it. :-) – kriegaex May 13 '20 at 11:55