3


I'm using Java Spring Mvc and Spring AOP to find the parameter names from the user.
I have a controller which get parameters from user and call a service.
I have an aspect that running before the service.
The aspect should check if username and apiKey parameters are exist.
Here is my code :

Controller :

@RequestMapping(method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody String getDomainWithFoundIn(@RequestParam (value="domain") String domain, @RequestParam (value="user") String user, @RequestParam (value="apiKey") String apiKey) throws JsonGenerationException, JsonMappingException, IOException {
    return domainService.getDomainDataWithFoundIn(domain, user, apiKey);
}

Domain Service Interface :

public interface IDomainService {
    public String getDomainDataWithFoundIn(String domainStr, String user, String apiKey);
}

DomainService :

@Override
@ApiAuthentication
public String getDomainDataWithFoundIn(String domainStr, String user, String apiKey) {
//Do stuff here
}

And my AOP class :

@Component
@Aspect
public class AuthAspect {
@Before("@annotation(apiAuthentication)") 
public void printIt (JoinPoint joinPoint, ApiAuthentication apiAuthentication) throws NoAuthenticationParametersException, UserWasNotFoundException {
        final MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        final String[] parameterNames = signature.getParameterNames();
        **//parameterNames is null here.**
}

In this case, I'd expect to get on my aspect the "domain", "user" and "apiKey" parameter names.
Any idea what am i missing here ?
Thanks,
Or.

ork
  • 209
  • 3
  • 9
  • 17
  • You've _kind of_ said what you'd expect. Now tell us what actually happens. – Sotirios Delimanolis Aug 10 '14 at 07:25
  • I wrote it on aspect class - I got null on String[] parameterNames instead the parameter names. – ork Aug 10 '14 at 07:28
  • How are you compiling your source code? – Sotirios Delimanolis Aug 10 '14 at 16:13
  • With eclipse on debug, internal maven plugin. – ork Aug 10 '14 at 16:27
  • 1
    I'd start by double checking that. Then try debugging and seeing where it goes to find the parameter names. With Spring 3.x, it will check byte code, but maybe in Spring 4 it uses the new `Method` methods to get `Parameter` objects. – Sotirios Delimanolis Aug 10 '14 at 16:29
  • I'm using spring 4.0.6.RELEASE and on debug mode it goes to MethodInvocationProceedingJoinPoint.getSignature(). And about compiling, I'm using eclipse, tomcat7 and maven, just running the debug. – ork Aug 10 '14 at 18:15
  • 1
    This happens when AOP is intersecting the interface, if it's a class parameter names are filled. This is probably because of using different proxy for interface and class by spring (CGLIB vs JDK) http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop-api.html#aop-pfb-proxy-types – Lukasz Frankowski Oct 31 '14 at 13:51

3 Answers3

6

As I've said in above comment, depending on proxy type you can or can't have access to parameter names. If your bean implements interface, the JDK proxy will be created by spring, and in this kind of proxy MethodSignature.getParameterNames() is null. If your bean doesn't implement interface, CGLIB proxy is created, where MethodSignature.getParameterNames() is filled.

If you can, you may switch to CGLIB proxy bean by removing bean interfaces and it should work.

I'm struggling with the same now, and I can't remove interfaces. I figured out different solution for this. On the interface I can mark my parameters by some custom annot:

interface MyInterface {
  void myMetod(@ParamName("foo") Object foo, @ParamName("bar") Object bar);
}

Now in AOP proxy I can get this information in:

MethodSignature.getMethod().getParameterAnnotations()
Lukasz Frankowski
  • 2,955
  • 1
  • 31
  • 32
  • Thanks for the explanation, now I know why `null` is always returned for parameter names... And the solution offered is a very nice workaround, but it seems not consistent with the principles of AOP with which codes that are not related to the logic should not be added. That being said, I have no better solution than yours. – YC_ Nov 25 '18 at 02:45
1

I could make this work in Eclipse with Java 8 only . Here's how:

  • Right Click on the project -> Properties -> Java Build Path -> Libraries tab and make sure you add there a JDK 8 instead of what you have now (in my case I had JDK_1.7.0_51 and replaced it with JDK_1.8.0_05). Apply changes.
  • Go to Java Compiler -> Check Enable project specific settings -> Check Use default compliance settings and set Compiler compliance level to 1.8. The same goes for Generated .class files compatibility and Source compatibility.
  • At the Classfile Generation section make sure to check Store method parameter names option (in my tests, I had all the options under Classfile Generation checked). The Store method parameter names option was available in my case only for a compliance level of 1.8. Click Ok.
  • Clean and re-compile your project.
  • I have, also, run my project on Tomcat 7 with JDK 8. No need to run it in Debug mode.

Tested this in STS 3.5.1 (Eclipse Kepler SR2 4.3.2).

Andrei Stefan
  • 51,654
  • 6
  • 98
  • 89
1

The simplest way is to set proxyTargetClass in your config file, i.e.

@EnableAspectJAutoProxy(proxyTargetClass = true)
Lu Fangjian
  • 49
  • 1
  • 6
  • I am not sure why this was downvoted. It works from the spring docs `To enable CGLIB, you need to set the attribute proxy-targetclass= true in aop:aspectj-autoproxy.` – rocky Nov 11 '17 at 01:04