JPA basic example with EntityManager , Spring
and Maven
Our pom.xml will be like this..
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hopcroft.examples.spring</groupId>
<artifactId>simpledao</artifactId>
<version>0.0.1-SNAPSHOT</version>
<pluginRepositories>
<pluginRepository>
<id>maven-annotation</id>
<url>http://maven-annotation-plugin.googlecode.com/svn/trunk/mavenrepo</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArguments>
<processor>org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor</processor>
</compilerArguments>
</configuration>
<version>2.3.2</version>
</plugin>
<plugin>
<groupId>org.bsc.maven</groupId>
<artifactId>maven-processor-plugin</artifactId>
<version>2.0.2</version>
<executions>
<execution>
<id>process</id>
<goals>
<goal>process</goal>
</goals>
<phase>generate-sources</phase>
<configuration>
<outputDirectory>src/main/generated-java</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/generated-java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>ejb3-persistence</artifactId>
<version>1.0.2.GA</version>
<type>pom</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.0.5.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.0.0.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>3.0.5.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.security</groupId>
<artifactId>jacc</artifactId>
<version>1.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.10</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.0.5.RELEASE</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.6.1</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.12.1.GA</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>3.5.0-Final</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>3.5.0-Final</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.codehaus.openxma</groupId>
<artifactId>dsl-platform</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>1.0.0.Final</version>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
Our application will
have the next structure
We have a domain model layer where there is a Car entity that mirrors the database
table.
Our car entity:
package com.hopcroft.examples.domain;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "Car")
public class Car {
@Id
@Column(name =
"id")
private long id;
@Column(name =
"company")
private String
company;
@Column(name =
"model")
private String
model;
@Column(name =
"price")
private long
price;
public void
setId(long id) {
this.id = id;
}
public long
getId() {
return id;
}
public String
getCompany() {
return
company;
}
public void
setCompany(String company) {
this.company =
company;
}
public String
getModel() {
return model;
}
public void
setModel(String model) {
this.model =
model;
}
public long
getPrice() {
return price;
}
public void
setPrice(long price) {
this.price =
price;
}
}
We have also a data access layer where there is a interface
called CarDao that defines the methods that we use to interact with our database.
This interface will be implemented by the CarDaoImpl.
In some of the later projects we have use a HibernateTemplate
object to get the data from our database. Instead of that we are going to use
an EntityManager instance. An EntityManager will be a instance
of an EntityManagerFactory within JPA. This type of factory means
the configuration used to access to our database.
To use JPA in our project we are going
to create a persistence unit in the META-INF/persistence.xml file. Within this
file we will have a specified persistence unit. What we should do is choosing
the transaction type. We need to use the provider that will implement JPA. In our case, we are going
to use Hibernate.
<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="JpaPersistenceUnit"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
</persistence-unit>
</persistence>
We need to configure our application context in the same way
we did when we used an Hibernate sessionFactory.
That means, we have to add a dataSource
within our context file where we define our url , user, password and the
database we are going to use. We define an entityManagerFactory
to which we pass the newly created dataSource.
This entityManagerFactory object
will be controlled by a transactionManager.
As we are using JPA we need a
org.springframework.orm.jpa.JpaTransactionManager.
There is also a component-scan element. We will explain it when we see our Dao.
Our context file is
as follows:
<?xml version="1.0" encoding="UTF-8"
standalone="no"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<bean
id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="com.mysql.jdbc.Driver"
p:url="jdbc:mysql://localhost/test"
p:username="root" p:password=""
p:initialSize="5" p:maxActive="10">
</bean>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
id="entityManagerFactory">
<property
name="dataSource" ref="dataSource" />
</bean>
<context:component-scan base-package="com.hopcroft.examples.dao">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Repository" />
</context:component-scan>
<bean
class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property
name="entityManagerFactory" ref="entityManagerFactory"
/>
</bean>
<tx:annotation-driven mode="aspectj"
transaction-manager="transactionManager" />
<context:spring-configured />
<context:annotation-config />
</beans>
After take a look to
our configuration files we need to explain our Dao (interface and its
implementation).
package com.hopcroft.examples.dao;
import java.util.List;
import org.springframework.dao.DataAccessException;
import com.hopcroft.examples.domain.Car;
public interface CarDao {
public
List<Car> getCars() throws DataAccessException;
public Car
getCar(Long carId) throws DataAccessException;
}
package com.hopcroft.examples.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.hopcroft.examples.domain.Car;
@Repository
public class CarDaoImpl implements CarDao {
protected
EntityManager entityManager;
public
EntityManager getEntityManager() {
return
entityManager;
}
@PersistenceContext
public void
setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
@Transactional
public
List<Car> getCars() throws DataAccessException {
Query query =
getEntityManager().createQuery("select c from Car c");
List<Car> resultList = query.getResultList();
return
resultList;
}
@Transactional
public Car
getCar(Long carId) throws DataAccessException {
return
getEntityManager().find(Car.class, carId);
}
}
There is no much to say about the carDao
interface. Two methods that we implement within the CarDaoImpl class. We need
to explain a couple of things.
First of all we notice that CarDaoImpl is
annotated as @Repository. This is an annotation we use to say
to the Spring context that our CarDaoImpl is included within
its context as a component. Besides the @Repository annotation
there are a @Service annotation and a @Controller
one. Every annotation extends to the @Component annotation.
There is a meaning difference among them, @Repository will
indicate our Spring context that we want to add a Dao bean, @Controller
a controller and @Service … easy to guess. Do you remenber
thecomponent-scan element within our testApplicationContext file?, in this file
we tell Spring we are going to incluide as beans every single
class with the @Repository annotation, in our case, CarDaoImpl
car.
The second annotation we notice is @PersistenceContext.
It is in the EntityManager setter method. We get an EntiyManagerFactory
object we need for address our database.
We can notice that our methods are annontated as
transactional. That means our methods belong to a unique transaction that will
be management by the transactionManager we explained in our
context file.
Our method logic is quite straightforward. We
have a couple of methods, the first one list every car we have stored in our
database and the second one use an id to find a specified car. To that we have
to use an entityManager. As with HibernateTemplate,
our entityManager class will have some basic methods like
persist, refresh ó remove. Once our application is created we are going to make
a test class.
package com.hopcroft.examples.test;
import java.util.List;
import java.util.logging.Logger;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import
org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.test.context.ContextConfiguration;
import
org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.hopcroft.examples.dao.CarDao;
import com.hopcroft.examples.domain.Car;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"/testApplicationContext.xml" })
public class CarTest {
@Autowired
private CarDao
carDao;
private Logger
logger = Logger.getLogger("myLog");
private Long id;
@Before
public void init()
{
// carNumber =
carDao.getCars().size();
id = 1L;
}
@Test
public void
listCarsTest() {
List<Car> cars = carDao.getCars();
//
logger.info("Cars: " + cars.size());
Assert.assertNotNull(cars);
Assert.assertEquals(15, cars.size());
}
@Test
public void
getCarTest() {
Car car =
carDao.getCar(id);
Assert.assertEquals(id.longValue(), car.getId());
Assert.assertEquals("Boxster", car.getModel());
}
}
We annotate our class as always, pointing that we are going
to use JUnit4 and the context file we
have already created. We are going to get our CarDao from the Spring context. We have some
method that we are going to test from a Maven test
configuration within STS.