java - Spring Bean Injection Failing Due To Proxy -
spring version: 3.2.4.release , 3.2.9.release
mockito version: 1.8.5
i've been trying introduce h2 tests old project integration testing, , i've been running few issues. due way transactions propagating, needed mock out autowired class. i've done before, i'm running severe problems. following error message being thrown when initialising test:
org.springframework.beans.factory.beancreationexception: error creating bean name 'com.stuff.xmlitcase': injection of resource dependencies failed; nested exception org.springframework.beans.factory.beannotofrequiredtypeexception: bean named 'theprocessor' must of type [com.stuff.xmlbatchfileprocessor], of type [$proxy118] @ org.springframework.context.annotation.commonannotationbeanpostprocessor.postprocesspropertyvalues(commonannotationbeanpostprocessor.java:307)
diving bit deeper, turns out the bean in-fact proxy. if check abstractbeanfactory (round line 239), can see proxy:
sharedinstance = {$proxy117@7035} "com.stuff.xmlbatchfileprocessor@66c540d0" h = {org.springframework.aop.framework.jdkdynamicaopproxy@7039}
the problem is, i've no clue coming from. i've gone on config , dependencies, , can't find anywhere should happening.
project setup
unfortunately can't give sample project this, i'll go on test configuration. have root class extend tests:
@runwith(springjunit4classrunner.class) @contextconfiguration(locations = {"classpath:/spring/spring-test-context.xml"}) @transactionconfiguration(transactionmanager = "transactionmanager", defaultrollback = true) public abstract class abstractintegrationtest { }
this loads in spring config , rolls transactions after each test.
the spring config nothing strange either, though there 1 difference between other module , one. transaction manager , session factory:
<bean id="transactionmanager" class="org.springframework.orm.hibernate3.hibernatetransactionmanager"> <property name="sessionfactory" ref="hibernatesessionfactory"/> </bean> <bean id="hibernatesessionfactory" class="org.springframework.orm.hibernate3.annotation.annotationsessionfactorybean"> ... </bean>
in other module, i'm using entitymanagerfactory, , different transaction manager:
<bean id="transactionmanager" class="org.springframework.orm.jpa.jpatransactionmanager"> <property name="entitymanagerfactory" ref="entitymanagerfactory"/> </bean> <bean id="entitymanagerfactory" class="org.springframework.orm.jpa.localcontainerentitymanagerfactorybean"> ... </bean>
the class has autowired fields, , usual @service annotation:
@service(value = "theprocessor") public final class xmlbatchfileprocessor extends batchfileprocessor implements ixmlbatchprocessor {
finally, actual test follows:
public class xmlitcase extends abstractintegrationtest { @resource(name = "theprocessor") @injectmocks private xmlbatchfileprocessor xmlprocessor; @mock private processhelper processhelper; @before public void setup() throws exception { mockitoannotations.initmocks(this); } @test public void test() throws exception { assert.assertnotnull(xmlprocessor); } }
if replace xmlbatchfileprocessor interface , autowire field, there aren't problems compiling. mockito, however, never replaces autowired bean mocked object. if did, wouldn't bother @resource annotations , naming service, avoiding proxy issue.
any assistance on appreciate. i'll focusing on session factory , differences there, it's quite possible i'm missing else entirely.
edit
going on sotirios' comment, had morning , indeed had missed xmlprocessor has @transactional
annotation, meaning class needs proxied. if remove final
declaration , let cglib enhance it, mockito replace bean when initmocks(this)
called. when method called, however, cglib seems replace beans spring enhanced versions, hence overwriting mockito version.
what correct way use both mockito , spring in integration test class @transactional
annotations?
alright, once realised class being proxied due @transactional
annotation, solution problem became clearer. needed unwrap proxy, , set mocked object directly on that:
so in abstractintegrationtest
:
/** * checks if given object proxy, , unwraps if is. * * @param bean object check * @return unwrapped object proxied, else object * @throws exception */ public final object unwrapproxy(object bean) throws exception { if (aoputils.isaopproxy(bean) && bean instanceof advised) { advised advised = (advised) bean; bean = advised.gettargetsource().gettarget(); } return bean; }
then in @before
:
@mock private processhelper processhelper; @before public void setup() throws exception { mockitoannotations.initmocks(this); ixmlbatchprocessor ixmlbatchprocessor = (ixmlbatchprocessor) unwrapproxy(xmlprocessor); reflectiontestutils.setfield(ixmlbatchprocessor , "processhelper", processhelper); }
this left @autowired
classes intact, while injecting correct mocked object.
Comments
Post a Comment