17

I have created my own annotation for classes: @MyAnnotation, and have annotated two classes with it.

I have also annotated a few methods in these classes with Spring's @Transactional. According to the Spring documentation for Transaction Management, the bean factory actually wraps my class into a proxy.

Last, I use the following code to retrieve the annotated beans.

  1. Method getBeansWithAnnotation correctly returns my declared beans. Good.
  2. The class of the bean is actually a proxy class generated by Spring. Good, this means the @Transactional attribute is found and works.
  3. Method findAnnotation does not find MyAnnotation in the bean. Bad. I wish I could read this annotation from the actual classes or proxies seamlessly.

If a bean is a proxy, how can I find the annotations on the actual class ?

What should I be using instead of AnnotationUtils.findAnnotation() for the desired result ?

Map<String,Object> beans = ctx.getBeansWithAnnotation(MyAnnotation.class);
System.out.println(beans.size());
// prints 2. ok !

for (Object bean: services.values()) {
  System.out.println(bean.getClass());
  // $Proxy

  MyAnnotation annotation = AnnotationUtils.findAnnotation(svc.getClass(), MyAnnotation.class);
  //
  // Problem ! annotation is null !
  //
}
Leonel
  • 28,541
  • 26
  • 76
  • 103

2 Answers2

14

You can find the real class of the proxied bean by calling AopProxyUtils.ultimateTargetClass.

Determine the ultimate target class of the given bean instance, traversing not only a top-level proxy but any number of nested proxies as well - as long as possible without side effects, that is, just for singleton targets.

dnault
  • 8,340
  • 1
  • 34
  • 53
10

The solution is not to work on the bean itself, but to ask the application context instead.

Use method ApplicationContext#findAnnotationOnBean(String,Class).

Map<String,Object> beans = ctx.getBeansWithAnnotation(MyAnnotation.class);
System.out.println(beans.size());
// prints 2. ok !

for (Object bean: services.values()) {
  System.out.println(bean.getClass());
  // $Proxy

  /* MyAnnotation annotation = AnnotationUtils.findAnnotation(svc.getClass(), MyAnnotation.class);
  // Problem ! annotation is null !
   */

  MyAnnotation annotation = ctx.findAnnotationOnBean(beanName, MyAnnotation.class);
  // Yay ! Correct !
}
Leonel
  • 28,541
  • 26
  • 76
  • 103
  • 10
    How do you find *methods* that have the given annotation? – David Harkness Jan 29 '13 at 20:14
  • This seems to (non-deterministically) only work part of the time, even though I'm running the same bundled application JAR multiple times on the same platform and JRE – Karsten Jul 13 '16 at 08:06