0

I have a controller class with one RequestMapping method which is taking String arguments. I want to pass this argument by using Spring AOP but its failing, I am getting null value when I am printing the value.

Tried with the below provided solution but its working with map but not with String.

Spring AOP pass argument of a controller method

@Controller
public class WelcomeController {
    @Autowired
    private FamilyService familyService;

    @RequestMapping(value = "/", method = RequestMethod.GET)
    public ModelAndView welcomePage(String welcomeMessage) {
        FamilyVO allFamilyMembers = familyService.getAllFamilyMembers();
        ModelAndView modelAndView = new ModelAndView("Index", "family", allFamilyMembers);
        List<String> familyMemberAges = new ArrayList<String>();
        for (int i = 0; i <= 100; i++) {
            familyMemberAges.add("" + i);
        }
        modelAndView.addObject("familyMemberAges", familyMemberAges);
        System.out.println(welcomeMessage);
        return modelAndView;
    }
}
@Component
@Aspect
public class WelcomeControllerAspect {
    @Before("execution(* com.kalavakuri.webmvc.web.controller.WelcomeController.welcomePage(..))")
    public void beforeWelcomePage(JoinPoint joinPoint) {
        joinPoint.getArgs()[0] = "Hellow";
        System.out.println(joinPoint.getArgs().length);
        System.out.println("Before welcomepage");
    }
}

I am expecting the value "Hello" when I print it in Controller class but printing null.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
user995656
  • 123
  • 1
  • 14

2 Answers2

2

A @Before advice is not meant to manipulate method parameters. In the example you linked to it only works because the argument is a mutable object, namely a Map. A String is immutable, though, you cannot edit it.

Having said that, what should you do? Use an @Around advice which was designed for that kind of thing. There you can decide how you want to proceed, e.g.

  • call the original method with original parameters,
  • call the original method with changed parameters,
  • do something before and/or after calling the original,
  • don't call the original method but return another result instead,
  • handle exceptions in the original method
  • or any mix of the above which makes sense (maybe you have multiple cases and if-else or switch-case).

I also suggest not to work directly on the Object[] of JoinPoint.getArgs() but to bind the relevant method parameter(s) to a named and type-safe advice parameter via args(). Try this:

package de.scrum_master.aspect;

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

@Component
@Aspect
public class WelcomeControllerAspect {
  @Around(
    "execution(* com.kalavakuri.webmvc.web.controller.WelcomeController.welcomePage(..)) && " +
    "args(welcomeMessage)"
  )
  public Object beforeWelcomePage(ProceedingJoinPoint joinPoint, String welcomeMessage) throws Throwable {
    System.out.println(joinPoint + " -> " + welcomeMessage);
    return joinPoint.proceed(new Object[] { "Hello AOP!" });
  }
}
kriegaex
  • 63,017
  • 15
  • 111
  • 202
0

You should use an @Around advice instead of a @Before. See this answer for more details.

Gustavo Passini
  • 2,348
  • 19
  • 25
  • Use same example but using `@Arroung` with same result: does not work. The argument from controller is null, but from `joinPoint` argument 0 is equals to argument type of function. – e-info128 Jul 14 '22 at 22:09
  • Hi @F-Natic. I had made a typo in m answer. It's `@Around`, not `@Aroung` or `@Arroung`. Just wanted to make sure there isn't a typo in your code too. The accepted answer above is much more complete than mine and should be easier to follow. – Gustavo Passini Jul 18 '22 at 13:54