Question

In the following code I am trouble with my injected EnitityManager, which always shows up as null;

public class GenericController extends AbstractController {

    @PersistenceContext(unitName = "GenericPU")
    private EntityManager em;

    protected ModelAndView handleRequestInternal(
            HttpServletRequest request,
            HttpServletResponse response) throws Exception {
        //(em == null) is always trigged
        if (em == null) throw new NullPointerException("em is null");
        Collection<Generic> Generics = em.createNamedQuery("Generic.findAll").getResultList();

        ModelAndView mav = new ModelAndView("Generic");
        mav.addObject(Generics); 
        return mav;
    }
}

Here is the bean definition, defined in dispatcher-servlet.xml.

<bean id="Generic" class="com.application.web.GenericController" />

EnitityManager should be injected based on tx:annotation-based, defined in the persistence-context.xml file.

<?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:tx="http://www.springframework.org/schema/tx"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
        <property name="url" value="removed" />
        <property name="username" value="removed" />
        <property name="password" value="removed" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="GenericPU" />
        <property name="dataSource" ref="dataSource" />
        <property name="jpaDialect">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
        </property>
        <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.SQLServerDialect" />
            </bean>
        </property>
    </bean>

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

    <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

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

</beans> 

The persistence-context is loaded from the applicationContext.xml

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
    <import resource="classpath:META-INF/persistence-context.xml"/>
</beans>

The classpath import is done because the ORM entities are included as a JAR file into the project. Note that I believe the persistence-context is being loaded, as Spring will not allow the application to be deployed if it can't parse its configuration files.

Here is my persistence.xml.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="CoolOrmJpaPU" transaction-type="RESOURCE_LOCAL">
    <class>com.application.orm.jpa.Generic</class>
    <!-- bunch more classes -->
  </persistence-unit>
</persistence>

And my web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.htm</url-pattern>
    </servlet-mapping>
    <session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    <welcome-file-list>
        <welcome-file>redirect.jsp</welcome-file>
    </welcome-file-list>
</web-app>

Can anyone help me out here?

Was it helpful?

Solution

I was lucky enough today to be able to speak with a consultant about this issue, he was able to help me sort the whole thing out.

So my problem is that Spring MVC was establishing two distinct contexts, one application context, defined in applicationContext.xml and one web context, defined in dispatcher-servlet.xml.

Beans from one context can not talk to beans in another context, thus when I initilized my persistence context inside of applicationContext.xml, I could not access it in beans loaded by dispatcher-servlet.xml, ie my controllers.

When Netbeans auto-generated the base to my Spring MVC it set this up by default. In some large web applications, it would make sense to separate the web part of the application in a context distinct from the rest of the logic (persistence, business code, etc). In my case, where I am trying to auto inject my entity manager directly into my controllers, this worked against me.

To fix the issue I moved the line

<import resource="classpath:META-INF/persistence-context.xml"/>

From the applicationContext.xml, to my dispatcher-servlet.xml. My controllers then were properly injected with EntityManagers from the @PersistanceContext annotation.

OTHER TIPS

I think you need a file persistence.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">

  <persistence-unit name="GenericPU">
     <class>com.domain.MyClass</class>
  </persistence-unit>

</persistence>

I think it will not work if the file has a different name, especially not since you don't tell the EntityManager factory the new name anywhere.

I used to work with an older spring version, when you had to put setProperty() to the bean and set the propery tag inside the spring-bean definition like:

<bean id="Generic" class="com.application.web.GenericController" />
    <property name="em" ref="entityManager" />
</bean>

Maybe you should work with the transactionManager or the entityManagerFactory beans...

PD: I personally prefer the old way of injecting dependencies.

Have you included

<context:annotation-config />

In your spring XML. Reference here

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top