Spring Data Rest – How to create a RestAPIs with JPA Many-to-Many relational entities | SpringBoot + MySql + HAL Browser

In the tutorial, JavaSampleApproach will guide how to build a Spring Data Rest application for Jpa Many-To-Many relational entities with SpringBoot.

Related posts:
Spring Data Rest – How to create a RestAPIs with JPA One-to-Many relational entities | SpringBoot + MySql + HAL Browser
How to access MySQL database with Spring Data Rest application
Spring JPA – Many to Many relationship

I. Technologies

– Java 8
– Maven 3.6.1
– Spring Tool Suite: Version 3.8.4.RELEASE
– Spring Boot: 1.5.4.RELEASE
– MySQL
– Hal Browser

II. Practice

The tutorial creates a SpringBoot project with 2 JPA entities {Student, Subject} which have Many-to-Many relationship. We use Spring Data Rest to build restfulAPIs for accessing MySQL data which are created by 2 entities. Then using HalBrowser to consume the rests.

Step to do:
– Create SpringBoot project
– Create Jpa entities
– Create Rest repositories
– Implement CommandLineRunner client
– Run and check results

spring data rest hal many to many - project structure

1. Create SpringBoot project

Using SpringToolSuite to create a SpringBoot project. Then add dependencies:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-rest-hal-browser</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

2. Create JPA entities

Create 2 JPA entities with Many-to-Many relationship {Student, Subject}:

– Student


package com.javasampleapproach.restdata.model;

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 Student {
	
	@Id
    @GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	private String name;
	
	@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "student_subject", joinColumns = @JoinColumn(name = "student_id", referencedColumnName = "id"), 
    inverseJoinColumns = @JoinColumn(name = "subject_id", referencedColumnName = "id"))
	private Set subjects;
	
	public Student(){
		
	}
	
	public Student(String name){
		this.name = name;
	}
	
	public Student(String name, Set subjects){
		this.name = name;
		this.subjects = subjects;
	}
	
	// name
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	// subjects
	public Set getSubjects() {
		return subjects;
	}
	
	public void setSubjects(Set subjects) {
		this.subjects = subjects;
	}
}

– Subject


package com.javasampleapproach.restdata.model;

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 Subject {
	
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
	private int id;
	private String name;
	
	@ManyToMany(mappedBy = "subjects", fetch = FetchType.EAGER)
	private Set students;
	
    public Subject(){
    }
    
    public Subject(String name){
    	this.name = name;
    }
    
    public Subject(String name, Set students){
    	this.name = name;
    	this.students = students;
    }
	
	// name
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	// students
	public Set getStudents() {
		return students;
	}
	
	public void setStudents(Set students) {
		this.students = students;
	}
}

3. Create Rest repositories

Create 2 rest repositories {StudentRepository, SubjectRepository}:

– StudentRepository


package com.javasampleapproach.restdata.repository;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import com.javasampleapproach.restdata.model.Student;

@RepositoryRestResource(collectionResourceRel = "student", path = "student")
public interface StudentRepository extends PagingAndSortingRepository {
}

– SubjectRepository


package com.javasampleapproach.restdata.repository;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import com.javasampleapproach.restdata.model.Subject;

@RepositoryRestResource(collectionResourceRel = "subject", path = "subject")
public interface SubjectRepository extends PagingAndSortingRepository {
}

– Open application.properties file, configure spring.datasource:


spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=12345
spring.jpa.generate-ddl=true

4. Implement CommandLineRunner client

In main class of the SpringBoot project, we use CommandLineRunner to init Student and Subject objects, then using StudentRepository to store them in MySql database.


package com.javasampleapproach.restdata;

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

import javax.transaction.Transactional;

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.javasampleapproach.restdata.model.Student;
import com.javasampleapproach.restdata.model.Subject;
import com.javasampleapproach.restdata.repository.StudentRepository;

@SpringBootApplication
public class SpringRestDataManyToManyApplication implements CommandLineRunner{
	
	@Autowired
	StudentRepository studentRepository;

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

	@Transactional
	@Override
	public void run(String... arg0) throws Exception {
		
		// delete all tables
		studentRepository.deleteAll();
		
		Student jack = new Student("Jack");
		Student peter = new Student("Peter");
		
		Subject math = new Subject("Mathematics");
		Subject computer = new Subject("Compter");
		
		Set subjects = new HashSet();
		subjects.add(math);
		subjects.add(computer);
		
		jack.setSubjects(subjects);
		peter.setSubjects(subjects);
		
		studentRepository.save(jack);
		studentRepository.save(peter);
	}
}

5. Run and check results

Build and Run the SpringBoot project with commandlines {mvn clean install, mvn spring-boot:run}.
The SpringBoot application creates 3 tables {student, subject, student_subject}:

– Make a request http://localhost:8080:

spring data rest hal many to many - first request

– Select all students:

spring data rest hal many to many - select all students

– Select all subjects:

spring data rest hal many to many - select all subjects

– Select all subjects of a student:

spring data rest hal many to many - select all subjects of a students

– Select all students a subject:

spring data rest hal many to many - select all students of a subject

III. Sourcecode

SpringRestDataManyToMany

3 thoughts on “Spring Data Rest – How to create a RestAPIs with JPA Many-to-Many relational entities | SpringBoot + MySql + HAL Browser”

  1. Hi,

    The above tutorial worked perfectly but with only 1 limitation.
    If the many to many table has extra columns it doesn’t work, Do you have any solution for that?

    Regards,

Leave a Reply

Your email address will not be published. Required fields are marked *