Spring Data JPA

Posted on Updated on

Spring Data JPA provides a more cleaner approach of using JPA for DAO layer. It removes boilerplate code and developers can concentrate on actual logic.

Our DataModel

07 September 2013 PM 06-14-30
First create a maven project and add below dependencies:

<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.mumz.test.springdata.jpa</groupId>
	<artifactId>SpringDataJPA</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<properties>
		<spring.version>3.2.4.RELEASE</spring.version>
		<spring.data.version>1.3.4.RELEASE</spring.data.version>
		<hibernate.version>4.2.5.FINAL</hibernate.version>
		<jpa.version>1.0.1.FINAL</jpa.version>
		<querydsl.version>3.2.3</querydsl.version>
		<junit.version>4.8.2</junit.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>${junit.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-jpa</artifactId>
			<version>${spring.data.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate.javax.persistence</groupId>
			<artifactId>hibernate-jpa-2.0-api</artifactId>
			<version>${jpa.version}</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-entitymanager</artifactId>
			<version>${hibernate.version}</version>
		</dependency>
		<dependency>
			<groupId>com.mysema.querydsl</groupId>
			<artifactId>querydsl-jpa</artifactId>
			<version>${querydsl.version}</version>
		</dependency>
		<dependency>
			<groupId>javax.inject</groupId>
			<artifactId>javax.inject</artifactId>
			<version>1</version>
		</dependency>
		<dependency>
			<groupId>commons-logging</groupId>
			<artifactId>commons-logging</artifactId>
			<version>1.1.3</version>
		</dependency>
		<dependency>
			<groupId>commons-pool</groupId>
			<artifactId>commons-pool</artifactId>
			<version>1.6</version>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<executions>
					<execution>
						<id>default-testCompile</id>
						<phase>test-compile</phase>
						<goals>
							<goal>testCompile</goal>
						</goals>
						<configuration>
							<source>1.6</source>
							<target>1.6</target>
						</configuration>
					</execution>
					<execution>
						<id>default-compile</id>
						<phase>compile</phase>
						<goals>
							<goal>compile</goal>
						</goals>
						<configuration>
							<source>1.6</source>
							<target>1.6</target>
						</configuration>
					</execution>
				</executions>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

Given our datamodel and maven dependcies ready, below is the Book Entity class. Book is a simple POJO with JPA annotations.

package com.mumz.test.springdata.jpa.entity;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * The Class Book.
 * 
 * @author prabhat.jha
 */
@Entity(name = "BOOK")
public class Book implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = -5163349208616552005L;

	/** The id. */
	private Long id = null;

	/** The name. */
	private String name = null;

	/** The author. */
	private String author = null;

	/**
	 * Gets the id.
	 * 
	 * @return the id
	 */
	@Id
	@Column(name = "ID")
	@GeneratedValue(strategy = GenerationType.AUTO)
	public Long getId() {
		return id;
	}

	/**
	 * Sets the id.
	 * 
	 * @param id
	 *            the new id
	 */
	public void setId(Long id) {
		this.id = id;
	}

	/**
	 * Gets the name.
	 * 
	 * @return the name
	 */
	@Column(name = "NAME")
	public String getName() {
		return name;
	}

	/**
	 * Sets the name.
	 * 
	 * @param name
	 *            the new name
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Gets the author.
	 * 
	 * @return the author
	 */
	@Column(name = "AUTHOR")
	public String getAuthor() {
		return author;
	}

	/**
	 * Sets the author.
	 * 
	 * @param author
	 *            the new author
	 */
	public void setAuthor(String author) {
		this.author = author;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#hashCode()
	 */
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((author == null) ? 0 : author.hashCode());
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (!(obj instanceof Book)) {
			return false;
		}
		Book other = (Book) obj;
		if (author == null) {
			if (other.author != null) {
				return false;
			}
		} else if (!author.equals(other.author)) {
			return false;
		}
		if (id == null) {
			if (other.id != null) {
				return false;
			}
		} else if (!id.equals(other.id)) {
			return false;
		}
		if (name == null) {
			if (other.name != null) {
				return false;
			}
		} else if (!name.equals(other.name)) {
			return false;
		}
		return true;
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Book [id=" + id + ", name=" + name + ", author=" + author + "]";
	}
}

The major difference from plain old JPA and "Spring Data JPA" is usage of repositories. A Repository provides you with the generic framework for dealing with persistence layer boilerplate code like below:

public void save(MyEntity myEntity){
    if(myEntity.getId() != null) {
        entityManager.merge(myEntity);
    } else {
        entityManager.persist(myEntity);
    }
}

Spring Data JPARepository provides you with enough generic services to take care of most of the scenarios. Given this let's write our Repository called as IBookRepository which is an interface and extends JpaRepository. JpaRepository is parameterized interface so we need to provide the Entity class and class of the identifier(Primary Key). In this case our Entity class is Book and identifier is Long.

package com.mumz.test.springdata.jpa.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.mumz.test.springdata.jpa.entity.Book;

/**
 * The Interface IBookRepository.
 * 
 * @author prabhat.jha
 */
public interface IBookRepository extends JpaRepository<Book, Long> {
	/**
	 * Find book by id.
	 * 
	 * @param bookId
	 *            the book id
	 * @return the book
	 */
	public Book findBookById(Long bookId);

	/**
	 * Find all books.
	 * 
	 * @return the list
	 */
	public List<Book> findAll();
}

Next we will write our Service interface IBookService and it's implementation class BookServiceImpl. IBookService is a plain interface and self-explanatory.

package com.mumz.test.springdata.jpa.service;

import java.util.List;

import com.mumz.test.springdata.jpa.entity.Book;

/**
 * The Interface IBookService.
 * @author prabhat.jha
 */
public interface IBookService {
	
	/**
	 * Save.
	 *
	 * @param book the book
	 * @return the book
	 */
	public Book save(Book book);
	
	/**
	 * Find book by id.
	 *
	 * @param bookId the book id
	 * @return the book
	 */
	public Book findBookById(Long bookId);
	
	/**
	 * Find all books.
	 *
	 * @return the list
	 */
	public List<Book> findAllBooks();
}

Next is our service implementation class BookServiceImpl. If you take a closer look you will see we don't have any EntityManager instead we have our IBookRepository. Same IBookRepository would be used to save and retrieve records.

package com.mumz.test.springdata.jpa.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.mumz.test.springdata.jpa.entity.Book;
import com.mumz.test.springdata.jpa.repository.IBookRepository;

/**
 * The Class BookServiceImpl.
 * 
 * @author prabhat.jha
 */
@Service(value = "bookService")
@Transactional
public class BookServiceImpl implements IBookService {

	/** The book repository. */
	@Autowired
	private IBookRepository bookRepository = null;

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.mumz.test.springdata.jpa.service.IBookService#save(com.mumz.test.springdata.jpa.entity.Book)
	 */
	@Override
	public Book save(Book book) {
		return bookRepository.save(book);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.mumz.test.springdata.jpa.service.IBookService#findBookById(java.lang.Long)
	 */
	@Override
	public Book findBookById(Long bookId) {
		return bookRepository.findBookById(bookId);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see com.mumz.test.springdata.jpa.service.IBookService#findAllBooks()
	 */
	@Override
	public List<Book> findAllBooks() {
		return bookRepository.findAll();
	}

	/**
	 * Gets the book repository.
	 * 
	 * @return the book repository
	 */
	public IBookRepository getBookRepository() {
		return bookRepository;
	}

	/**
	 * Sets the book repository.
	 * 
	 * @param bookRepository
	 *            the new book repository
	 */
	public void setBookRepository(IBookRepository bookRepository) {
		this.bookRepository = bookRepository;
	}
}

And finally our applicationContext.xml. Since we are using annotation driven configuration it is important to tell Spring where to search for our repositories and so that it can search and keep it ready for DI.

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

	<tx:annotation-driven />
	<jpa:repositories base-package="com.mumz.test.springdata.jpa" />
	<context:component-scan base-package="com.mumz.test.springdata.jpa" />
	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName">
			<value>oracle.jdbc.driver.OracleDriver</value>
		</property>
		<property name="url">
			<value>jdbc:oracle:thin:@localhost:1521:MYDB</value>
		</property>
		<property name="username">
			<value>MYUSER</value>
		</property>
		<property name="password">
			<value>MYPASSWORD</value>
		</property>
	</bean>

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

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

We also need persistence.xml since we are dealing with JPA.

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.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_2_0.xsd">
	<persistence-unit name="springdata" >
	</persistence-unit>
</persistence>

Finally our test class BookServiceTest

/**
 * 
 */
package com.mumz.test.springdata.jpa;

import static org.junit.Assert.assertNotNull;

import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestExecutionListeners;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.transaction.TransactionalTestExecutionListener;
import org.springframework.transaction.annotation.Transactional;

import com.mumz.test.springdata.jpa.entity.Book;
import com.mumz.test.springdata.jpa.repository.IBookRepository;
import com.mumz.test.springdata.jpa.service.IBookService;

/**
 * The Class BookServiceTest.
 *
 * @author prabhat.jha
 */
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({ TransactionalTestExecutionListener.class,
		DependencyInjectionTestExecutionListener.class })
@ContextConfiguration(locations = { "/META-INF/applicationContext.xml" })
@Transactional
@TransactionConfiguration(defaultRollback = false)
public class BookServiceTest {

	/** The last created book id. */
	private Long lastCreatedBookId = null;
	
	/** The book service. */
	@Autowired
	@Qualifier(value = "bookService")
	private IBookService bookService;

	/** The book repository. */
	@Autowired
	private IBookRepository bookRepository;

	/**
	 * Sets the up.
	 *
	 * @throws Exception the exception
	 */
	@Before
	public void setUp() throws Exception {
	}

	/**
	 * Tear down.
	 *
	 * @throws Exception the exception
	 */
	@After
	public void tearDown() throws Exception {
	}

	/**
	 * Test create book.
	 */
	@Test
	public void testCreateBook() {
		Book book = new Book();
		book.setName("Spring Data JPA - Reference Documentation");
		book.setAuthor("Oliver Gierke");
		book = this.getBookRepository().save(book);
		assertNotNull("Test failed create book returned null id",book.getId());
		lastCreatedBookId = book.getId();
	}

	/**
	 * Test find book by id.
	 */
	@Test
	public void testFindBookById() {
		Book book = this.getBookRepository().findBookById(lastCreatedBookId);
		assertNotNull(book);
	}

	/**
	 * Test find all books.
	 */
	@Test
	public void testFindAllBooks() {
		List<Book> books = this.getBookRepository().findAll();
		assertNotNull("Test failed findAllBooks returned null", books);
		if (books != null) {
			for (Book book : books) {
				System.out.println(book);
			}
		}
	}

	/**
	 * Gets the book service.
	 *
	 * @return the book service
	 */
	public IBookService getBookService() {
		return bookService;
	}

	/**
	 * Sets the book service.
	 *
	 * @param bookService the new book service
	 */
	public void setBookService(IBookService bookService) {
		this.bookService = bookService;
	}

	/**
	 * Gets the book repository.
	 *
	 * @return the book repository
	 */
	public IBookRepository getBookRepository() {
		return bookRepository;
	}

	/**
	 * Sets the book repository.
	 *
	 * @param bookRepository the new book repository
	 */
	public void setBookRepository(IBookRepository bookRepository) {
		this.bookRepository = bookRepository;
	}
}

Hope this helps!
N.B: You can download the code from Spring Data JPA

2 thoughts on “Spring Data JPA

    Abhishek said:
    September 7, 2013 at 10:23 PM

    Keep it up, your posts are pretty to the point and simple
    to understand technical underpinnings

    amar said:
    September 23, 2015 at 6:56 PM

    how to execute this code ??

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s