Leonel
Leonel

Reputation: 29219

Find annotation in Spring proxy bean

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 !
  //
}

Upvotes: 18

Views: 15270

Answers (2)

dnault
dnault

Reputation: 8909

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.

Upvotes: 16

Leonel
Leonel

Reputation: 29219

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 !
}

Upvotes: 11

Related Questions