Finding custom method level annotation in a Spring context

All I wanted to know was "all classes / methods in Spring beans that are annotated as @Versioned".

I created my annotation as

@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Versioned { ..... } 

This annotation works fine when I use Java reflection to search for methods like:

 for(Method m: obj.getClass().getMethods()){ if(m.isAnnotationPresent(Versioned.class)){ .... // Do something } 

But this does not work when I turn to Spring beans and try a similar check:

 public class VersionScanner implements ApplicationContextAware{ public void setApplicationContext(ApplicationContext applicationContext){ for(String beanName: applicationContext.getBeanDefinitionNames()){ for(Method m: applicationContext.getBean(beanName).getClass().getDeclaredMethods()){ if(m.isAnnotationPresent(Versioned.class){ // This is not WORKING as expected for any beans with method annotated } } } } } 

In fact, this code finds other annotations like @RequestMapping. I'm not sure what I am doing wrong with my custom annotation.

+8
java spring spring-mvc
source share
2 answers

Looking through my code, I realized that you are using Spring AOP with CGLIB Proxying. Thanks to this, your classes (which have methods annotated with @Versioned ) are proxied.

I tested this solution with your code base.

Use the following code and it should solve your problem. Find additional options below the code snippet:

 @Configuration public class VersionScanner implements ApplicationContextAware { public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { for (String beanName : applicationContext.getBeanDefinitionNames()) { Object obj = applicationContext.getBean(beanName); /* * As you are using AOP check for AOP proxying. If you are proxying with Spring CGLIB (not via Spring AOP) * Use org.springframework.cglib.proxy.Proxy#isProxyClass to detect proxy If you are proxying using JDK * Proxy use java.lang.reflect.Proxy#isProxyClass */ Class<?> objClz = obj.getClass(); if (org.springframework.aop.support.AopUtils.isAopProxy(obj)) { objClz = org.springframework.aop.support.AopUtils.getTargetClass(obj); } for (Method m : objClz.getDeclaredMethods()) { if (m.isAnnotationPresent(Versioned.class)) { //Should give you expected results } } } } } 

To define a proxy class:

  • For Spring AOP proxy using any proxy mechanism use org.springframework.aop.support.AopUtils#isAoPProxy
  • If you proxy using Spring CGLIB (not through Spring AOP), use org.springframework.cglib.proxy.Proxy#isProxyClass
  • If you are using a proxy server through a JDK proxy, use java.lang.reflect.Proxy#isProxyClass

I just wrote one if condition, which is enough in your case; but in the case of using several proxy programs, several if-else should be written based on the above information.

+6
source share

applicationContext.getBean(beanName).getClass() gives you a proxy class that Spring creates around your target class.

What you want is to get the target class, if any, from your Spring bean.

Spring provides a good utility class to resolve this name AopUtils.class.

Below you will learn how to use it:

 for(String beanName: applicationContext.getBeanDefinitionNames()){ Method[] methods = AopUtils.getTargetClass(applicationContext.getBean(beanName)).getDeclaredMethods(); for(Method m: methods){ if(m.isAnnotationPresent(Versioned.class){ } } } 

Note that you will need to import the spring-aop Maven dependency to get the AopUtils class:

 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> 
+4
source share

All Articles