views:

308

answers:

2

I'm trying to use JPA's Context Injection. Currently my code fails to have the context injected, throwing a NullPointerException:

Exception in thread "main" java.lang.NullPointerException at learn.spring.dao.ListingDao.findById(ListingDao.java:19)

Below is my code, anyone see what is wrong/missing? Thanks.

Spring Configuration xml:

<beans ....>

<tx:annotation-driven />
<context:annotation-config />
<aop:aspectj-autoproxy />

<bean id="listingDao" class="learn.spring.dao.ListingDao" />

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

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 <property name="persistenceUnitName" value="learnSpring" />
 <property name="dataSource" ref="dataSource" />
 <property name="jpaVendorAdapter">
  <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
   <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
   <property name="showSql" value="true" />
   <property name="generateDdl" value="true" />
  </bean>
 </property>
</bean>

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

DAO class:

package learn.spring.dao;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.transaction.annotation.Transactional;

import learn.spring.model.Registration;

@Transactional
public class ListingDao {
 public ListingDao() {}

 @PersistenceContext
 private EntityManager entityManager;

 public Registration findById(int id) {
  Query query = entityManager.createQuery("FROM Registration r WHERE r.memberId = ?1");
  query.setParameter(1, id);
  return (Registration) query.getSingleResult();
 }
}

peristence.xml file:

<?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"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">

<persistence-unit name="learnSpring" />

</persistence>

Class w/ "main" method:

public class Performance {

 public static void main(String[] args){
  ApplicationContext context = new ClassPathXmlApplicationContext("learn-spring.xml");
  Performer performer = (Performer) context.getBean("musician");
  performer.perform();
  ListingDao listingDao = new ListingDao();
  Registration registration = listingDao.findById(1);
  System.out.println("Member id = " + registration.getMemberId() + " Name = " + registration.getFirstName() + " " + registration.getLastName());
 }

}
+1  A: 

Your problem is that your ListingDao isn't part of the spring context.

All the classes which you want to benefit from the spring's dependecy injection must be instantiated by spring. When you instantiate your ListingDao with the new operator, your object isn't part of the spring context and it doesn't receive an automatic EntityManager.

So the solution would be to get the ListingDao from the context, like you did with the performer:

ListingDao listingDao = (ListingDao) context.getBean("listingDao");

As a sidenote - avoid accessing the spring context directly. i.e. avoid lines like the above. Use annotations to inject your dependencies, rather than requesting them, because you are thus turning a Dependency Injection framework into a Service Locator.

Bozho
After answering your comment above it hit me that I was circumventing DI by manually instantiating the object... I was so focused on all the other aspects that I overlooked the most obvious.
Dan
A: 

When you instantiate ListingDAO, you're doing it outside of the spring context - so spring never gets a chance to wire up the EntityManager.

You should replace:

  ListingDao listingDao = new ListingDao();

with:

  ListingDao listingDao = (ListingDao) context.getBean("listingDao");
Chris Gummer