Spring Boot + JPA/Hibernate Many to Many mapping example

Hello everyone, In this tutorial, we will learn how to implement many-to-many entity mapping using JPA/Hibernate with Spring Boot, Spring Data JPA, and H2DB database.



Project Structure 

See the final project structure of this tutorial.


Maven[pom.xml] 

A Project Object Model or POM is the fundamental unit of work in Maven. It is an XML file that contains information about the project and configuration details utilized by Maven to build the project. It contains default values for most projects. Some of the configurations that can be designated in the POM is the project dependencies, the plugins or goals that can be executed, the build profiles, and so on. Other information such as the project version, description, developers, mailing lists, and such can withal be designated.

<?xml version="1.0" encoding="UTF-8"?>
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.1.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot_jpa_hibernate_manytomanymapping</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot_jpa_hibernate_manytomanymapping</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<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>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

application.properties

spring.datasource.url=jdbc:h2:mem:knfdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
logging.level.org.hibernate.SQL=DEBUG
logging.level.org.hibernate.type=TRACE
spring.h2.console.enabled=true

Modal class[Author.class]

package com.knf.dev.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToMany;

@Entity
public class Author {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;

@ManyToMany(mappedBy = "authors", fetch = FetchType.LAZY)
private Set<Book> books = new HashSet<>();

public Author() {
}

public Author(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}

public Author(String firstName, String lastName, Set<Book> books) {
this.firstName = firstName;
this.lastName = lastName;
this.books = books;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public Set<Book> getBooks() {
return books;
}

public void setBooks(Set<Book> books) {
this.books = books;
}

}

Model class[Book.class]

package com.knf.dev.model;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;

@Entity
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private String isbn;
private String publisher;

@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinTable(name = "author_book", joinColumns =
@JoinColumn(name = "book_id"),
inverseJoinColumns = @JoinColumn(name = "author_id"))
private Set<Author> authors = new HashSet<>();

public Book() {
}

public Book(String title, String isbn, String publisher) {
this.title = title;
this.isbn = isbn;
this.publisher = publisher;
}

public Book(String title, String isbn, String publisher,
Set<Author> authors) {
this.title = title;
this.isbn = isbn;
this.publisher = publisher;
this.authors = authors;
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getIsbn() {
return isbn;
}

public void setIsbn(String isbn) {
this.isbn = isbn;
}

public String getPublisher() {
return publisher;
}

public void setPublisher(String publisher) {
this.publisher = publisher;
}

public Set<Author> getAuthors() {
return authors;
}

public void setAuthors(Set<Author> authors) {
this.authors = authors;
}

}

Repository[BookRepository.class]

package com.knf.dev.repository;

import java.util.List;

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

import com.knf.dev.model.Book;

@Repository
public interface BookRepository extends JpaRepository<Book, Long> {
List<Book> findByIsbn(String isbn);

}

DTO[BookDto.class]

package com.knf.dev.dto;

import java.util.HashSet;
import java.util.Set;

public class BookDto {

private Long id;
private String title;
private String isbn;
private String publisher;

private Set<AuthorDto> authors = new HashSet<>();

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getTitle() {
return title;
}

public void setTitle(String title) {
this.title = title;
}

public String getIsbn() {
return isbn;
}

public void setIsbn(String isbn) {
this.isbn = isbn;
}

public String getPublisher() {
return publisher;
}

public void setPublisher(String publisher) {
this.publisher = publisher;
}

public Set<AuthorDto> getAuthors() {
return authors;
}

public void setAuthors(Set<AuthorDto> authors) {
this.authors = authors;
}

}

DTO[AuthorDto.class]

package com.knf.dev.dto;

public class AuthorDto {
private Long id;
private String firstName;
private String lastName;

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getFirstName() {
return firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public AuthorDto(Long id, String firstName, String lastName) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}

}

Controller[HomeController.class]

package com.knf.dev.controller;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.knf.dev.dto.AuthorDto;
import com.knf.dev.dto.BookDto;
import com.knf.dev.model.Author;
import com.knf.dev.model.Book;
import com.knf.dev.repository.BookRepository;

@RestController
@RequestMapping("books")
public class HomeController {
@Autowired
BookRepository bookRepository;

@GetMapping
public List<BookDto> findAll() {

return bookMapper(bookRepository.findAll());

}

@PostMapping
public Boolean save(@RequestBody Book book) {
try {
bookRepository.save(book);
return true;
} catch (Exception e) {
System.out.println(e);
return false;
}

}

private List<BookDto> bookMapper(List<Book> book) {
List<BookDto> bookDto = new ArrayList<>();

for (Book bk : book) {
BookDto dto = new BookDto();
dto.setId(bk.getId());
dto.setIsbn(bk.getIsbn());
dto.setPublisher(bk.getPublisher());
dto.setTitle(bk.getTitle());
Set<AuthorDto> dtoAuthor = new HashSet<>();
for (Author auth : bk.getAuthors()) {
AuthorDto author = new AuthorDto(auth.getId(),
auth.getFirstName(), auth.getLastName());
dtoAuthor.add(author);
}
dto.setAuthors(dtoAuthor);
bookDto.add(dto);
}
return bookDto;
}
}

Main Driver Class[Application.class]

package com.knf.dev;

import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.knf.dev.model.Author;
import com.knf.dev.model.Book;
import com.knf.dev.repository.BookRepository;

@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
BookRepository bookRepository;

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

@Override
public void run(String... args) throws Exception {
// Insert dummy datas
Book book = new Book();
Set<Author> authorList = new HashSet<>();
Author author1 = new Author();
author1.setFirstName("Sibin");
author1.setLastName("knf");
authorList.add(author1);
book.setAuthors(authorList);
book.setIsbn("23423dfd");
book.setPublisher("knf");
book.setTitle("Java");
bookRepository.save(book);

}
}

Run & Test 

Run Spring Boot application with the command: mvn spring-boot:run

Add New Book



Fetch All Book





Comments