Sunday, September 30, 2012

Spring Data JPA


Spring JPA is part of the umbrella Spring Data project that makes it easy to easily implement JPA based repositories.
Spring Data project abstracts away the basic data management concept. It provides in build basic CRUD operation functionalities and  also provide automatic query generator strategies.

The central interface in Spring Data repository abstraction is Repository. It provides some sophisticated functionality around CRUD for the entity managed. Spring Data have persistence technology specific sub-interfaces to include additional technology specific methods.
In our case , we will be using JpaRepository  sub interface, where we declare an interface extending the technology specific Repository sub-interface JpaRepository  and type it to the domain class it shall handle.

Steps to create Spring data JPA repository:
  • Define domain class
  • Defining repository interfaces 
  • Defining query methods
  • Creating repository instances(Configuration)

Define domain class
As a very first step, we will define a domain class using JPA annotation as
  @Entity
  @Table(name = "employee")
  public class Employee implements Serializable {...}

Define repository interface
Then next step will define a domain class specific repository interface. Spring Data JPA provides a repository programming model that starts with an interface per managed domain object, The name of the interface should be  domain class name with Repository keyword as EmployeeRepository.

  @Repository
  public interface EmployeeRepository extends JpaRepository<Employee, Integer> {}

It's got to extend JpaRepository and be typed to the domain class(employee) and an ID type Integer.
The basic CRUD operation like findOne, findAll, save, delete on Employee entity will be implicitly available and Spring Data JPA repository infrastructure will scan the classpath for this interface and create a bean for it.

Defining query methods
Some time, we might need user defined business method like findByEmployeeName() , findByGender() etc. In this case we have to explicitly declare the method in interface and Spring data might use appropriate query strategy to generate query and give the result.
 Developer can also provide named or native query along with method declaration using @Query annotation as mentioned below


  @Query("select e from Employee e where e.strEmployeeName like ?1")
  public List<Employee> getEmployeeByName(String strEmployeeName);


Creating repository instances(Configuration)
To have Spring create a bean that implements repository specific interface, all you need to do is use the Spring JPA namespace and activate the repository support using the appropriate element:

  <jpa:repositories base-package="com.sarf.repository" />

This scans all packages below com.sarf.repository for interfaces extending JpaRepository and creates a Spring bean for it that is backed by an implementation of JpaRepository



Now we will start writing some code to understand the implementation side of Spring Data JPA. We will keep our entity as simple as possible. We will create a Employee POJO for our example as


Employee.java
package com.sarf.domain;

import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "employee")
public class Employee implements Serializable {

 private static final long serialVersionUID = 1L;
 @Id
 @GeneratedValue(strategy = GenerationType.AUTO)
 @Column(name = "employeeId")
 private int nEmployeeId;
 @Column(name = "employeeName")
 private String strEmployeeName;

 public int getnEmployeeId() {
  return nEmployeeId;
 }
 
 public void setnEmployeeId(final int nEmployeeId) {
  this.nEmployeeId = nEmployeeId;
 }

 public String getStrEmployeeName() {
  return strEmployeeName;
 }

 public void setStrEmployeeName(final String strEmployeeName) {
  this.strEmployeeName = strEmployeeName;
 }
}


EmployeeRepository.java
package com.sarf.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.sarf.domain.Employee;

@Repository
public interface EmployeeRepository 
  extends JpaRepository<Employee, Integer> {
 }
Defining this interface serves two purposes: First, by extending JpaRepository we get a bunch of generic CRUD methods into our type that allows saving Employee, deleting them and so on. Second, this will allow the Spring Data JPA repository infrastructure to scan the classpath for this interface and create a Spring bean for it.

Next we will be writing service class to access the repository instance and perform CRUD operation for Employee entity. I will prefer writing CXF web service to use repository directly.


EmployeeRestService.java
package com.sarf.restservice;

import javax.ws.rs.Consumes;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

@Path("/employee-service/")
@Produces(MediaType.TEXT_PLAIN)
public interface EmployeeRestService {

 @POST
 @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
 @Path("addEmployee")
 public void addEmployee(@FormParam("employeeName") String employeeName);

 @GET
 @Consumes(MediaType.TEXT_PLAIN)
 @Path("getEmployee/{emplId}")
 public String getEmployee(@PathParam("emplId") Integer nEmplId);
}

Next we will be write the implementation class for this RESTful webservice interface.

EmployeeRestServiceImpl.java
package com.sarf.restservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.sarf.domain.Employee;
import com.sarf.repository.EmployeeRepository;

@Service
@Transactional
public class EmployeeRestServiceImpl implements EmployeeRestService {

 @Autowired
 EmployeeRepository employeeRepository;

 public void addEmployee(String employeeName) {
  Employee employee = new Employee();
  employee.setStrEmployeeName(employeeName);
  this.employeeRepository.saveAndFlush(employee);
 }
 
 public String getEmployee(Integer nEmplId) {
  Employee employee = this.employeeRepository.findOne(nEmplId);
  return "Id : "+employee.getnEmployeeId()
                        +", Name: "+employee.getStrEmployeeName();
  
 }
}

appContext.xml
web.xml


persistence.xml



index.jsp


addEmployee.jsp