This tutorial guides you through on building simple REST APIs using Spring Data JPA and Spring Boot. At the end of this tutorial, you would be able to write the applications with Spring Data JPA using Spring Boot.
In our earlier tutorials we have covered about Spring Data JPA and JPA frameworks. But, this tutorial uses Spring Boot for building and running the application. Also I have written core concepts of Spring Data Common project in this tutorial.
Table of Contents
Here is the list of sections covered in this tutorial.
- What is Spring Data?
- Spring Boot and Spring Data JPA
- Spring Data Repositories
- CrudRepository
- Repository
- PagingAndSortingRepository
- JpaRepository vs CrudRepository
- Query Methods
- Domain Class
- REST API
- Service Layer
- Spring Boot Application
- Download Source Code
- Conclusion
What is Spring Data?
Spring Data is a high level project developed by Spring community aimed at simplifying the data access operations for the applications. There are several sub-projects maintained for the individual stores to have its own implementation of repositories.
If you are using Spring Data in your project, you are not going to write most of the low level data access operations like writing SQL query, DAO classes, Â etc. Spring Data will generate everything dynamically at run-time by creating the proxy instances of your abstract repositories and perform the required operations. What you write is the abstract interfaces that define the required operations.
In this tutorials we will be using one of the sub project Spring Data JPA. Other than that Spring Data has the following sub-projects:
- Spring Data Commons
- Spring Data MongoDB
- Spring Data Redis
- Spring Data Solr
- Spring Data Gemfire
- Spring Data REST
- Spring Data Neo4j
Release Train
Spring Data project has several store specific projects as mentioned above. Needless to say, each of the above module has its own release cycle and team working on for the improvements. When you are downloading the dependencies for your application, each module mentioned above should have the compatibility with each other.
To resolve the compatibility issue, a BOM (Bill of Materials) is published with a curated set of dependencies on the individual project. The release trains have names, not versions, to avoid confusion with the sub-projects.
The latest release named as Gosling-RELEASE
and you have to add the following entries in your pom.xml
file.
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-releasetrain</artifactId> <version>Gosling-RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
Spring Data JPA
Spring Data JPA, it is part of the Spring Data family, aims to provide the JPA based repositories that aims to simplify the implementation of data access layer using JPA.
Spring Boot and Spring Data JPA
I am going to write a simple REST APIs for managing a book store application and store the details in H2 database, an in-memory database most commonly used for the development purposes. My final pom.xml file would look like this:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.5.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies>
If you look at the above configurations,
spring-boot-starter-parent
loads all the default configurations required for the basic spring boot applications.spring-boot-starter-data-jpa
dependency will download the files required for spring data jpa.spring-boot-starter-web
is required because it is web based application to expose the REST endpoints.
The above configurations sufficient to get started developing our simple REST APIs application using Spring Data JPA.
In the coming sections I will explain some of the interfaces in spring data and the purpose of them.
Spring Data Repositories
When you are working with spring data technologies, it is important to understand the repositories concept. Spring data provides the abstract repositories, that are implemented at run-time by the spring container and perform the CRUD operations. As a developer we have to just provide the abstract methods in the interface. This reduces the amount of boilerplate code required to write data access layers.
The following are the three base interfaces defined in the spring data commons project.
Repository
It is the central interface in the spring data repository abstraction. This is a marker interface. If you are extending this interface, you have to declare your own methods and the implementations will be provided by the spring run-time. For this interface also we have to pass two parameters:type of the entity and type of the entity’s id field. This is the super interface for CrudRepository.
CrudRepository
CrudRepository provides methods for the CRUD operations. This interface extends the Repository interface. When you define CrudRepository, you have to pass the two parameters: type of the entity and type of the entity’s id field. This interface has the following methods:
S save(S entity)- T findOne(ID primaryKey)
- Iterable findAll()
- Long count()
- void delete(T entity)
- boolean exists(ID primaryKey)
If you are extending the CrudRepository
, there is no need for implementing your own methods. Just extend this interface and leave it as blank. Required implementations are provide at run time.
Look at our example:
public interface BookRepository extends JpaRepository<Book,Long> { }
We have used JpaRepository
, which is the special version specific to the JPA technology. Unless until you are using any of the JPA specific things in your applications, it is highly recommended to use the CrudRepository
, because it will not tie your application with any specific store implementations.
The above code is sufficient to perform the basic operations like find, save, delete.
PagingAndSortingRepository
This is extension of CrudRepository. It is specialized version for the paging operations. The implementation of this class look like this:
public interface PagingAndSortingRepository<T, ID extends Serializable> extends CrudRepository<T, ID> { Iterable<T> findAll(Sort sort); Page<T> findAll(Pageable pageable); }
JpaRepository vs CrudRepository
Both, JpaRepository and CrudRepository are base interfaces in Spring Data. Application developer has to choose any of the base interfaces for your own repository. It has two purposes,
- One is to allow spring data to create proxy instance for your repository interface.
- Second one is to inherit the maximum default functionality from the base interfaces without declaring your own methods.
When we look at both of the interfaces, the clear differences are:
- CrudRepository is part of Spring Data Commons project and declared under the package
org.springframework.data.repository
. Where as JpaRepository is part of store specific implementation and declared under the packageorg.springframework.data.jpa.repository
. - CrudeRepository extnds from Repository interface. Where as JpaRepository extends from PagingAndSortingRepository which inturen extends from the CrudeRepository.
- JpaRepository returns
List
type of entities and CrudRepository returnsIterable
type of entities. - It is general recommendation that not to use the store specific base interfaces as they expose the underlying persistence technology and tighten the coupling between them and the repository. It is always good idea to choose any of the generic base interfaces like CrudRepository or PagingAndSortungRepository.
The below diagram shows the repository module structure.
Query Methods
- Query methods are used for finding the information from database and that are declared in the repository interface.
- Query methods can return one result or more than one result.
- This also supports passing parameter to database queries by sending through parameter binding or named parameters.
- If you want to implement query methods, implement Repository interface and write your own methods.
Here is a simple example of how to write query methods:
public interface BookOwnRepository extends Repository<Book,Long>{ List<Book> findByName(String name); List<Book> findByPrice(long price); List<Book> findByNameAndAuthor(String name, String author); }
- Using query methods are most convenient way to write our own queries to fetch data from the database. Spring data jpa allows more powerful query formation using the methods names and parameter.
- In the above example class, we have used only a few naming conventions are forming the query.
- findBy… – this is the prefix, anything follows this prefix will be used for framing the query
- findByName – In this method, only the matching names are returned. Here we are pasing only one parameter name.
- findByNameAndAuthor – In this method, we are using the “And” to add more information to the query by search either using name or author. In the similar way, you can use the “Or” delimiter.
Domain Class
Here is the simple domain class Book used for this tutorial.
Book.java
@Entity public class Book implements Serializable{ private static final long serialVersionUID = 1L; @Id long id; @Column(name=&quot;name&quot;) String name; @Column(name=&quot;author&quot;) String author; @Column(name=&quot;price&quot;) long price; //Getters and Setters Here }
@Entity
used for marking that this POJO is used as entity in the database.
REST API
I have written a simple REST API by annotating @RestController (this annotation introduced from Spring 4.0). This class will be interface between client application and the database layer. It exposes the API for add, find, list and delete books to the database.
Look at the example code:
@RestController @RequestMapping(value = &quot;/books&quot;) public class BooksController { @Autowired private BookService bookService; @RequestMapping(value = &quot;/add/{id}/{name}/{author}/{price}&quot;) public Book addBook(@PathVariable int id, @PathVariable String name, @PathVariable String author, @PathVariable long price) { Book book = new Book(); book.setId(id); book.setName(name); book.setAuthor(author); book.setPrice(price); bookService.saveBook(book); return book; } @RequestMapping(value = &quot;/delete/{id}&quot;) public void deleteBook(@PathVariable int id) { Book book = new Book(); book.setId(id); bookService.delete(id); } @RequestMapping(value = &quot;/&quot;) public List<Book> getBooks() { return bookService.findAll(); } @RequestMapping(value = &quot;/{id}&quot;) public Book getBook(@PathVariable int id) { Book book = bookService.findOne(id); return book; } @RequestMapping(value = &quot;/search/name/{name}&quot;) public List<Book> getBookByName(@PathVariable String name) { List<Book> books = bookService.findByName(name); return books; } @RequestMapping(value = &quot;/search/price/{price}&quot;) public List<Book> getBookByPrice(@PathVariable int price) { List<Book> books = bookService.findByPrice(price); return books; } @RequestMapping(value = &quot;/search/{name}/{author}&quot;) public List<Book> getBookByNameAndAuthor(@PathVariable String name, @PathVariable String author) { List<Book> books = bookService.findByNameAndAuthor(name, author); return books; } }
There is no explanation required for this class, as we have already covered in detail about the RestControllers and Spring Rest Services.
- Also Read : Integration Testing REST API using Spring Boot
Service Layer
I have written a service layer that will be in between REST API and Spring Data repositories. This is not a good practice to directly invoke the data access APIs from our REST, so I have written service layer for that purpose.
BookService.java
public interface BookService { public List<Book> findAll(); public void saveBook(Book book); public Book findOne(long id); public void delete(long id); public List<Book> findByName(String name); public List<Book> findByNameAndAuthor(String name, String author); public List<Book> findByPrice(long price); }
BookServiceImpl.java
@Service @Transactional public class BookServiceImpl implements BookService{ @Autowired private BookRepository bookRepository; @Autowired private BookOwnRepository bookOwnRepository; public List<Book> findAll(){ return bookRepository.findAll(); } public List<Book> findByName(String name){ return bookOwnRepository.findByName(name); } public List<Book> findByPrice(long price){ return bookOwnRepository.findByPrice(price); } public List<Book> findByNameAndAuthor(String name, String author){ return bookOwnRepository.findByNameAndAuthor(name,author); } public void saveBook(Book book){ bookRepository.save(book); } public Book findOne(long id){ return bookRepository.findOne(id); } public void delete(long id){ bookRepository.delete(id); } }
- We would require
@Transaction
annotation to perform the database transactions. @Service
annotation to indicate that it is service class- @Autowired is used for injecting the repository dependency to service layer.
- One thing if you note, I have injected both the repositories in the service layer. I have used both of them only for the example purpose, in your application you better choose any one repository type and write everything on the single repository.
- This service class is merely a delegation mode to invoke the repositories.
Spring Boot Application
Note : This example application for Spring Data JPA using Spring Boot is continuously improved and updated in the same location. So, there could be variation in this tutorial and what is actually you are seeing in the source code. But, everything works fine :).
Here is the final piece of code to bootstrap this application using spring boot. Ensure that this class is written in the same or above the level of package. When you run the spring boot application, it will consider the package where main class is located as the base package and start the @ComponentScan from that package.
Here is the package structure of the application:
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
- You can run this application through command line using the command spring-boot:run
If you have any issues on running this application, please contact me.
- Also Read : Complete Guide for Spring Boot Actuator (Production read features for spring boot applications exist out of the box)
Download the Source Code
Conclusion
In this tutorial I have explained how to write REST APIs using Spring Data JPA and Spring Boot frameworks. I hope this tutorial will be much useful and complete guide for learning Spring Data JPA. If you have any difficulty in understanding any of the concepts, please contact me through comments section. Enjoy working with spring data and power of simplicity.