11

In my Request i have a parameter name "accessToken", how do i get request parameter value from ProceedingJoinPoint ?

public Object handleAccessToken(ProceedingJoinPoint joinPoint) throws Throwable { 
    final Signature signature = joinPoint.getStaticPart().getSignature();
    if (signature instanceof MethodSignature) {
        final MethodSignature ms = (MethodSignature) signature;
        String[] params = ms.getParameterNames();
        for (String param : params) {
            System.out.println(param);
            // here how do i get parameter value using param ?
        }
    }
}

Calling method:

public MyResponse saveUser(
    @RequestParam("accessToken") String accessToken,
    @RequestBody final UserDto userDto
) {
    // code 
}

I want to get this access token in AOP.

Thanks in advance.

kriegaex
  • 63,017
  • 15
  • 111
  • 202
Shamseer PC
  • 787
  • 2
  • 9
  • 20
  • 1
    Please provide more information, e.g. the aspect pointcut and one or more samples of code to be intercepted, the parameter type and parameter position (such as first, second, third parameter when counting from left/right of the method signature). Then I will provide an elegant answer with parameter binding instead of ugly `getArgs()` or reflection code. – kriegaex Dec 30 '14 at 14:35
  • Thanks for the reply, i was trying to validate accessToken .in my rest application i am sending acceeesToken with request body some thing like {"accessToken":"myValue"} i need to retrieve that access token from ProceedingJoinPoint. – Shamseer PC Jan 01 '15 at 08:17
  • 1
    I would like to see code, not a description in prose. I am an AspectJ expert, not a Spring one. – kriegaex Jan 01 '15 at 12:10
  • i just edited my question .. added calling method source code . – Shamseer PC Jan 05 '15 at 09:58
  • Please also show the pointcut on the advice and also the class/aspect names and packages they reside in. Share not just snippets, please, but give me a big picture, ideally an [SSCCE](http://sscce.org/). Please also answer my earlier question with regard to parameter positions and also tell me if there can be more than one parameter with an access token annotation per method. – kriegaex Jan 05 '15 at 10:00
  • I would also like to know how to safely identify the parameter. I would guess by the annotation parameter, i.e. "accessToken" in `@RequestParameter`, not by variable name which can easily change and does not seem to be very reliable. Magic parameter names are a bad idea. – kriegaex Jan 05 '15 at 10:08

2 Answers2

30

Okay, Shamseer, I just have a little sparetime, so I am trying to answer your question without you answering all my questions from my comments. The way I go about this is that I will not use parameter names, but try to match on parameters with an annotation @RequestParam("accessToken"), i.e. I will match on the annotation type and value with a magic name of "accessToken" rather than a method parameter name which might change due to a simple refactoring of someone who is unaware of your aspect, due to stripping debug information from the class file during compilation or due to obfuscation.

Here is some self-consistent sample code which was tested against AspectJ, not Spring AOP, but the syntax of the latter is a subset of the former one's syntax anyway:

Sample class with main method:

There are three methods, all of which have a @RequestParam annotation on one of the parameters, but only two of those have the magic value of "accessToken". They should be matched regardless of the parameter type (one String and one int), but the one with @RequestParam("someParameter") should not be matched. Strictly speaking, all method executions are matched, but runtime reflection eliminates the undesired ones. If your annotations would be on class or method level or on parameter types, we could match them directly in the pointcut without reflection, but in the case of parameter annotations this is beyond AspectJ's current (v1.8.4) capabilities and we have to use reflection, unfortunately.

package de.scrum_master.app;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

public class MyResponse {
    public MyResponse saveUser(
        @RequestParam("accessToken") String accessToken,
        @RequestBody final UserDto userDto
    ) {
        return this;
    }

    public MyResponse doSomething(
        @RequestParam("someParameter") String text,
        @RequestBody final UserDto userDto
    ) {
        return this;
    }

    public MyResponse doSomethingElse(
        @RequestParam("accessToken") int number
    ) {
        return this;
    }

    public static void main(String[] args) {
        MyResponse myResponse = new MyResponse();
        myResponse.doSomething("I am not a token", new UserDto());
        myResponse.saveUser("I am a token", new UserDto());
        myResponse.doSomethingElse(12345);
    }
}

Dummy helper class to make the code compile:

package de.scrum_master.app;

public class UserDto {}

Aspect:

Please note that my catch-all pointcut execution(* *(..)) is just for illustration. You should narrow it down to the methods you actually want too match.

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.bind.annotation.RequestParam;

@Aspect
public class AccessTokenAspect {
    @Around("execution(* *(..))")
    public Object handleAccessToken(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        System.out.println(thisJoinPoint);
        Object[] args = thisJoinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getStaticPart().getSignature();
        Method method = methodSignature.getMethod();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        assert args.length == parameterAnnotations.length;
        for (int argIndex = 0; argIndex < args.length; argIndex++) {
            for (Annotation annotation : parameterAnnotations[argIndex]) {
                if (!(annotation instanceof RequestParam))
                    continue;
                RequestParam requestParam = (RequestParam) annotation;
                if (! "accessToken".equals(requestParam.value()))
                    continue;
                System.out.println("  " + requestParam.value() + " = " + args[argIndex]);
            }
        }
        return thisJoinPoint.proceed();
    }
}

Console output:

execution(void de.scrum_master.app.MyResponse.main(String[]))
execution(MyResponse de.scrum_master.app.MyResponse.doSomething(String, UserDto))
execution(MyResponse de.scrum_master.app.MyResponse.saveUser(String, UserDto))
  accessToken = I am a token
execution(MyResponse de.scrum_master.app.MyResponse.doSomethingElse(int))
  accessToken = 12345

See also this answer on a related, but somewhat simpler question with similar code.

Community
  • 1
  • 1
kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Maybe you want to refactor your code and make the access token a class of its own rather than a simple string. This way you could work in a type-safe way and also easily match pointcuts against a parameter type rather than on variable names or annotation values. – kriegaex Jan 06 '15 at 12:01
  • @kriegaex I want to create a generic method for the above code, but I am facing a problem with that as I am unable to pass `AnnotationType` into my method for the line `if (!(annotation instanceof RequestParam {AnnotationType}))` How can I pass RequestParam as a parameter to your code – KNDheeraj Apr 01 '19 at 07:08
  • Comments on 4 years old questions are not a good tool to ask & answer new questions, related or not. I suggest you create a new question with an [MCVE](http://stackoverflow.com/help/mcve), linking to my answer here and explaining precisely what you want to do and where/how it fails. Thank you. – kriegaex Apr 01 '19 at 09:44
  • If you want the argNames refer https://stackoverflow.com/a/49155868/234110 does something like this `String[] argNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames();` – Anand Rockzz Jul 06 '21 at 20:35
  • 1
    I know that, and I explained already that it is a bad idea, because the resulting aspect would be (a) bad design, (b) brittle (breaking if someone renames a method parameter), (c) in this case unnecessary because we can simply match the parameter's annotation, (d) not working if compiled without debug info. – kriegaex Jul 07 '21 at 05:05
12

To get Arguments that you get in as a parameter to method, your can try something like:

Object[] methodArguments = joinPoint.getArgs();
SMA
  • 36,381
  • 8
  • 49
  • 73
  • Excuse me for my questions, I do not know if my question is correct or not? does the getArgs () method use Reflection to retrieve parameters? – fatemeakbari May 23 '21 at 04:47