2013-05-07 13 views
6

I test di scrittura per le mie classi DAO utilizzando JPA, con Hibernate come provider JPA e Spring 3.2. Non sono in grado di iniettare correttamente il gestore di entità, ottengo una NullPointerException quando provo ad accedervi. La mia implementazione GenericDAO si presenta così:Spring non riesce a iniettare factory gestore entità

@Repository 
public class GenericDAOImpl implements GenericDAO { 

    @PersistenceContext(unitName="unitname") 
    private EntityManager entityManager; 

    public EntityManager getEntityManager() { 
     return entityManager; 
    } 


    public void setEntityManager(EntityManager entityManager) { 
     this.entityManager = entityManager; 
    } 

    // NullPointerException when calling this, entityManager is null 
    public Query createNamedQuery(String name) { 
     return entityManager.createNamedQuery(name); 
    }   

    // many other methods.... 
} 

La classe del test è simile al seguente:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = { "/com/main/resources/root-context.xml", "/com/main/resources/servlet-context.xml"}) 
public class TestModel { 

    @Before 
    public void setUp() throws Exception{ 
     ... 
    } 

    @Test 
    public void test(){ 
     ... 
    } 
} 

mio root-context.xml è la seguente:

<?xml version="1.0" encoding="UTF-8"?> 
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:beans="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" 
    xsi:schemaLocation=" 
     http://www.springframework.org/schema/aop 
     http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
     http://www.springframework.org/schema/beans 
     http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
     http://www.springframework.org/schema/context 
     http://www.springframework.org/schema/context/spring-context-3.0.xsd 
     http://www.springframework.org/schema/mvc 
     http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd   
     http://www.springframework.org/schema/tx 
     http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
     " 
> 

    <!-- Root Context: defines shared resources visible to all other web components --> 

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> 
     <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
     <property name="username" value="root" /> 
     <property name="password" value="root" /> 
    </bean> 

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> 
     <property name="persistenceUnitName" value="unitname" /> 
     <property name="dataSource" ref="dataSource" /> 
     <property name="packagesToScan" value="com.main" /> 
     <property name="jpaVendorAdapter"> 
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> 
       <property name="showSql" value="true" /> 
       <property name="generateDdl" value="false" /> 
       <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect" /> 
      </bean> 
     </property> 
    </bean> 

    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> 
     <property name="entityManagerFactory" ref="entityManagerFactory" /> 
    </bean> 

    <bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" /> 



    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="false" /> 
    <context:component-scan base-package="com.main" /> 
    <context:annotation-config /> 

</beans> 

ho ha provato diversi approcci senza successo, anche aggiungendo PersistenceAnnotationBeanPostProcessor come suggerito in altre domande SO. Tutte le altre cose sembrano funzionare bene: Hibernate crea le tabelle del database, il contesto è caricato, ecc. Cosa sto facendo male?

Edit: l'analisi dello stack è la seguente:

java.lang.NullPointerException 
    at com.main.model.dao.JPAImpl.GenericDAOImpl.createNamedQuery(GenericDAOImpl.java:119) 
    at com.main.model.bo.DescriptorBO.persist(DescriptorBO.java:52) 
    at com.main.webmodule.JSONSerializer.deserialize(JSONSerializer.java:149) 
    at com.main.tests.TestModel.test(TestModel.java:86) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:601) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) 
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) 
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:300) 
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) 
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) 
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 

Ed ecco il persistence.xml:

<?xml version="1.0" encoding="UTF-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> 
    <persistence-unit name="unitname" transaction-type="RESOURCE_LOCAL"> 
     <provider>org.hibernate.ejb.HibernatePersistence</provider> 
     <mapping-file>META-INF/jpql/NamedQueries.xml</mapping-file> 


     <class>com.main.model.Account</class> 
     <class>com.main.model.Action</class> 
     <class>com.main.model.Device</class> 
     <class>com.main.model.DeviceDescriptor</class> 
     <class>com.main.model.Event</class> 
     <class>com.main.model.File</class> 
     <class>com.main.model.Rule</class> 
     <class>com.main.model.StateVar</class> 
     <class>com.main.model.Argument</class> 
     <exclude-unlisted-classes>false</exclude-unlisted-classes> 


     <properties> 

      <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> 
      <property name="hibernate.connection.username" value="root"/> 
      <property name="hibernate.connection.password" value="root"/> 
      <property name="hibernate.connection.provider_class" value="org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider" /> 
      <property name="hibernate.connection.autocommit" value="true"/> 
      <property name="hibernate.connection.release_mode" value="auto"/> 
      <property name="hibernate.connection.url" value="jdbc:mysql://127.0.0.1:3306/testweb"/> 
      <property name="hibernate.hbm2ddl.auto" value="create"/> 

      <property name="hibernate.c3p0.min_size" value="1" /> 
      <property name="hibernate.c3p0.max_size" value="10" /> 
      <property name="hibernate.c3p0.acquire_increment" value="1" /> 
      <property name="hibernate.c3p0.idle_test_period" value="300" /> 
      <property name="hibernate.c3p0.max_statements" value="0" /> 
      <property name="hibernate.c3p0.timeout" value="100" /> 

      <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/> 

     </properties> 




    </persistence-unit> 
</persistence> 
+0

Invia il tuo stacktrace. –

+0

Mostraci il tuo 'persistence.xml' – falsarella

+0

Hai il' root-context.xml' e 'ContextLoaderListener' configurato nel tuo web.xml? Vedi http://stackoverflow.com/q/9856721/1064325 e http://stackoverflow.com/q/1132565/1064325 – falsarella

risposta

7

Sono finalmente riuscito a risolvere il problema. Istanziare GenericDAO ho usato un'annotazione autowired, in questo modo:

@Autowired 
private GenericDAO genericDao; 

ma la classe in cui questo accade, chiamato DescriptorBO, è esemplificato in questo modo:

DescriptorBO descrBO = new DescriptorBO(...); 

sfuggendo così completamente dal controllo della Contenitore primavera Cambiare questo in:

@Autowired 
private DescriptorBO descrBO; 

e aggiungendo le definizioni appropriate fagiolo alla radice-context.xml:

<bean name="descriptorBO" class="com.main.model.bo.DescriptorBO"> 
    <property name="genericDao" ref="genericDao" /> 
</bean> 

<bean name="genericDao" class="com.main.model.dao.JPAImpl.GenericDAOImpl" /> 

risolto il problema. Ora EntityManager viene iniettato correttamente.

Lezione imparata: se primavera non iniettare l'EntityManager (o qualsiasi altro oggetto iniettato) verificare che tutta la gerarchia degli oggetti sopra l'oggetto è gestito da primavera, i. e. istanziato dai bean nel contesto dell'applicazione, direttamente o utilizzando l'annotazione Autowired. Verifica di non utilizzare il nuovo operatore per istanziare nessuno di quegli oggetti !!

Problemi correlati