Skip to content
Advertisement

Spring fails to inject entity manager factory

I writing tests for my DAO classes using JPA, with Hibernate as JPA provider, and Spring 3.2. I am not able to inject the entity manager correctly, I get a NullPointerException when trying to access it. My GenericDAO implementation looks like this:

@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....
}

The class of the test looks like this:

@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(){
        ...
    }
}

My root-context.xml is the following:

<?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>

I’ve tried several approaches without success, even adding the PersistenceAnnotationBeanPostProcessor as suggested in other SO questions. All other things seem to work fine: Hibernate creates the database tables, the context is loaded, etc. What I am doing wrong?

Edit: the stack trace is the following:

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)

And here is the 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>

Advertisement

Answer

I’ve finally managed to solve the problem. To instantiate GenericDAO I used an autowired annotation, this way:

@Autowired
private GenericDAO genericDao;

but the class where this happens, called DescriptorBO, was instantiated this way:

DescriptorBO descrBO = new DescriptorBO(...);

and thus escaped completely from the control of the Spring container. Changing this into:

@Autowired
private DescriptorBO descrBO;

and adding the appropriate bean definitions to the root-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" /> 

solved the problem. Now the EntityManager is injected properly.

Lesson learnt: if Spring does not inject the EntityManager (or any other injected object) check that all the object hierarchy above your object is managed by Spring, i. e. instantiated from beans in the application context, either directly or using the Autowired annotation. Check that you do not use the new operator to instantiate any of those objects!!

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement