Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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>
like image 794
joanlofe Avatar asked May 07 '13 10:05

joanlofe


People also ask

How to inject an EntityManager object in a spring bean?

We can inject an EntityManager object in a Spring Bean such as repository, service or controller… using @Autowired annotation. @Repository public class TutorialRepository { @Autowired private EntityManager entityManager; } Spring Data JPA will initialize EntityManagerFactory for default persistence unit at runtime.

What happens when entitymanagerfactory is closed in JPA?

Once the EntityManagerFactory is closed or application shutdowns, all its EntityManager s are closed. How to access JPA Entity Manager? We can inject an EntityManager object in a Spring Bean such as repository, service or controller… using @Autowired annotation.

What is the difference between EntityManager and entitymanagerfactory?

EntityManager is used to interact with persistence context and EntityManagerFactory interacts with entity manager factory. Using EntityManager methods, we can interact with database.

How do I use @persistencecontext with an EntityManager?

This example shows use of @PersistenceContext to have an EntityManager with an EXTENDED persistence context injected into a @Stateful bean. A JPA @Entity bean is used with the EntityManager to create, persist and merge data to a database. The entity itself is simply a pojo annotated with @Entity.


1 Answers

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

like image 57
joanlofe Avatar answered Oct 05 '22 17:10

joanlofe