Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find annotation in Spring proxy bean

Tags:

spring

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 !
  //
}
like image 317
Leonel Avatar asked Jun 06 '11 19:06

Leonel


People also ask

How do I get annotations from BeanDefinition?

Access the BeanFactory. Look up the BeanDefinition associated with each bean. Check if the source of the BeanDefinition is an AnnotatedTypeMetadata, which means we'll be able to access the annotations of the bean.

What is the @bean annotation?

@Bean is a method-level annotation and a direct analog of the XML <bean/> element. The annotation supports most of the attributes offered by <bean/> , such as: init-method , destroy-method , autowiring , lazy-init , dependency-check , depends-on and scope .

What is use of @bean annotation in Spring?

Spring @Bean Annotation is applied on a method to specify that it returns a bean to be managed by Spring context. Spring Bean annotation is usually declared in Configuration classes methods. In this case, bean methods may reference other @Bean methods in the same class by calling them directly.

What is difference between @bean and @autowired?

@Bean is just for the metadata definition to create the bean(equivalent to tag). @Autowired is to inject the dependancy into a bean(equivalent to ref XML tag/attribute).


2 Answers

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.

like image 95
dnault Avatar answered Sep 20 '22 12:09

dnault


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 !
}
like image 25
Leonel Avatar answered Sep 21 '22 12:09

Leonel