lunes 5 de marzo de 2007

Maldito autowiring

El otro día estaba haciendo unos tests que implicaban accesos a la base de datos para probar que la capa de servicio funcionaba de manera correcta. Ya que necesitaba acceso a la base de datos, mi test extendía la clase AbstractTransactionalDataSouceSpringContextTest que proporciona Spring, hasta aquí todo correcto.

Para los tests, siempre tengo un fichero application-testing.xml donde defino todos los beans que necesito para el testing. Como necesitaba una serie de beans que ya tenia en mis contextos hice un copy & and paste felizmente hacia mi application-testing.xml.
  1. <bean id="A" class="examples.A">
  2. <bean id="AManager" class="org.springframework.transaction.interceptor.Tran
  3. sactionProxyFactoryBean">
  4. ...
  5. <property name="target" ref="A"/>
  6. ...
  7. </bean>
El test no funcionaba. La consola me devolvia un excepción lanzada por Spring diciendo que existian dos beans del mismo tipo.
  1. There are 2 beans of type [interface examples.A] for autowire by type.
  2. There should have been exactly 1 to be able to autowire property 'A' of bean
  3. 'examples.A'.
  • El bean que implementa la interfaz A (id = A)
  • El bean que és el target de la transacción, el cual és un proxy de A.
En los contextos de la aplicación hay veces que tengo más de un bean que es del mismo tipo que otro, por lo que no entendia el por qué del error.

El problema estaba en que no recordaba que por defecto, todas las clases que extienden la clase AbstractDependencyInjectionSpringContextTests y sus subclases tienen por defecto un autowiring inicializado a byType, en lugar del no autowiring que tienen los contextos principales. Lo leí hace tiempo en la documentación pero la verdad es que ni me acordaba.
  1. <bean id="A" class="examples.A">
  2. <bean id="AManager" class="org.springframework.transaction.interceptor.Tran
  3. sactionProxyFactoryBean">
  4. ...
  5. <property name="target">
  6. <bean class="examples.A"/>
  7. </property>
  8. ...
  9. </bean>
Otra solución es poner el autowiring a byName.

Hay que estar al loro con estas cosas, si es que no sé donde estará mi memória...