Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring @Autowired fails in case of Cobertura instrumented class

Question

Cobertura instrumentation is breaking springs autowiring in a specific case. Does anyone know how to resolve this?

Scenario

  • I am running MVN 3.0.4 with the cobertura-maven-plugin version 2.5.1.
  • mvn test runs without issues
  • mvn compile, package etc also runs without issues.
  • mvn cobertura:cobertura also ran without any issues up until the addition of 2 new features which introduced a number of new classes, including two new com.mycompany.executor executor classes. (Example: MyHappyExecutor and MySadExecutor was added in addition to the existing MyExecutor)
  • Excluding MyExecutor from the cobertura instrumentation process seems to fix autowiring
  • Checking the spring autowiring output confirms that the correct beans are getting autowired.

Point of failure

Autowiring fails when attempting to autowire the instrumented version of myExecutor in myService. This worked fine before adding MyHappyExecutor and MySadExecutor. MyHappyExecutor and MySadExecutor are autowired and used in MyExecutor exclusively.

I have attached the exception output below. Please not that class and package names have been edited.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myService': Injection of autowired dependencies failed; 
nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.executor.MyExecutor com.mycompany.service.impl.MyServiceImpl.myExecutor; 
nested exception is java.lang.IllegalArgumentException: Can not set com.mycompany.executor.MyExecutor field com.mycompany.service.impl.MyServiceImpl.myExecutor to $Proxy20

Conclusion

Something in the Cobertura instrumentation process messes up Springs autowiring.

Update 1

Forcing CGLIB class proxies changes the error type to a "java.lang.NoClassDefFoundError" error. This is affects the standard test goal as well as the Cobertura goal.

<aop:config proxy-target-class="true"/>

Update 2

Here is the output from springs startup process for the 3 classes in question.

2012-11-01 16:21:51 INFO  [main] Overriding bean definition for bean 'myExecutor': replacing [Generic bean: class [com.mycompany.executor.MyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.MyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
2012-11-01 16:21:51 INFO  [main] Overriding bean definition for bean 'happyExecutor': replacing [Generic bean: class [com.mycompany.executor.HappyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.HappyExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
2012-11-01 16:21:51 INFO  [main] Overriding bean definition for bean 'sadExecutor': replacing [Generic bean: class [com.mycompany.executor.SadExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] with [Generic bean: class [com.mycompany.executor.SadExecutor]; scope=; abstract=false; lazyInit=false; autowireMode=1; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [configuration.xml]] - (DefaultListableBeanFactory.java:623)
like image 908
elyzion Avatar asked Oct 26 '12 02:10

elyzion


1 Answers

Another option is to have the executors implement an interface (let's say Executor) and inject using interface in MyService. Spring will know how to build the proxy so that it implements the interface. Most of the times I prefer this approach to proxyTargetClass.

like image 196
Tavi Laies Avatar answered Sep 30 '22 13:09

Tavi Laies