Many-to-Many Relationship in Spring Boot Rest + JPA

In this article, we will learn about the Many-to-Many relationship in JPA and its implementation in a Spring Boot Application. Let’s make a start!

@ManytoMany annotation

A many-to-many relationship occurs when multiple records in a table are associated with multiple records in another table. @ManytoMany annotation defines a many-valued association with many-to-many multiplicity. As per the official documentation:

Every many-to-many association has two sides, the owning side and the non-owning, or inverse, side. The join table is specified on the owning side. If the relationship is bidirectional, the non-owning side must use the mappedBy element of the ManyToMany Annotation to specify the relationship field or property of the owning side.

Unidirectional or Bidirectional?

In JPA, we use the @ManyToMany annotation to model Many to Many Relationships. It could either be Uni-directional or Bi-directional.

  • In a unidirectional association, only one entity points to another.
  • In a bidirectional association, both entities point to each other.

If you are learning about Hibernate, you might also be interested in the following tutorials:

Illustration using an Employees Portal Example

Let’s take an example of an Employees Portal for a University. An Employee can be a Teacher and a Chairman at the same time. Likewise, the role of Teacher and Chairman can assign to several employees from different departments. This is how a Many-to-Many relationship works.

Let’s consider the two entities Users and Role, to understand the Many-to-Many relationships in the scenario under consideration. Consequently, here is the simplest form of the Entity-Relationship Diagram:


Database Structure

In our example, we are using the PostgreSQL database as the RDMS. On a side note, have you tried creating a table with the name “User” in Postgres? It would not work as User is the keyword in Postgres!

Returning to the ER Diagram, we have users table with id as the Primary Key and another table role with id as the Primary Key. There is also join table called users_roles responsible for connecting the two sides using the Foreign Keys user id and role id.

Initialize Project Structure

Create a Maven Spring Boot Project in any of your favourite IDE. Refer to this article for more details.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="" xmlns:xsi=""
        <!-- lookup parent from repository -->
    <description>Many to Many Relationship Example in Spring Boot Application</description>

spring.jpa.hibernate.ddl-auto = create true

Define the Domain Model Classes

Create model classes for Users and Role with the JPA Annotations. Later on execution, Spring and JPA will handle the rest for you.


package com.manytomanyrelationship.domain;

import javax.persistence.*;
import java.util.Collection;

public class Users {
    @GeneratedValue(strategy = GenerationType.AUTO)
    Integer id;
    String username;
    String password;

    @JoinTable(name = "users_roles", joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "role_id", referencedColumnName = "id"))
    private Collection<Role> roles;

    public Users() {


    public Users(String username, String password, Collection<Role> roles) {
        this.username = username;
        this.password = password;
        this.roles = roles;

    public String getUsername() {
        return username;

    public void setUsername(String username) {
        this.username = username;

    public String getPassword() {
        return password;

    public void setPassword(String password) {
        this.password = password;

    public Collection<Role> getRoles() {
        return roles;

    public void setRoles(Collection<Role> roles) {
        this.roles = roles;


package com.manytomanyrelationship.domain;

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

public class Role {
    @GeneratedValue(strategy = GenerationType.AUTO)
    Integer id;
    String name;

    public Role(Integer id, String name) { = id; = name;

    public Role(String name) {
        super(); = name;

    public Role() { // TODO Auto-generated constructor stub }


    public String getName() {
        return name;

    public void setName(String name) { = name;

The role is a simple Model class with no information about Users. However, we have used @ManyToMany annotation in a Users entity, making a Unidirectional Many to Many Mapping. Moreover, navigation is only possible from one side.

  • The annotation @Entity indicates that the classes are JPA entities.
  • The attribute id is marked with @Id and @GeneratedValue annotations in both classes. Firstly, @Id annotation denotes that this is the primary key. The latter annotation defines the primary key generation strategy with a strategy type as AUTOINCREMENT.
  • The @ManyToMany annotation is applied to the List of Role attribute in the Users class, indicating many-to-many relationship between the two entities. Furthermore, using CascadeType.ALL assures cascading means after the persistence of Users tuples, the persistence of Role tuples also occurs.
  • In addition, to the @ManyToMany annotation, the @JoinTable annotation is used. The @JoinTable annotation serves the purpose of creating a users_role table resulting in connecting the Users and Role entity. The parameter joinColumn will hold the primary key of this Users entity (the Owning side) whereas inverseJoinColumns will hold the primary key of the other entity (the inverse of the relationship), i.e. Role in our example.

Define the Rest Controller



import com.manytomanyrelationship.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

public class UsersController {
private UsersService usersService;

public ResponseEntity<Object> getAllUsers() {
return usersService.getAllUsers();

Define the Service Class


package com.manytomanyrelationship.service;

import com.manytomanyrelationship.domain.Users;
import com.manytomanyrelationship.repository.UsersRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import java.util.List;

public class UsersService {

    private UsersRepository usersRepository;

    public ResponseEntity<Object> getAllUsers() {
        List<Users> dbUsers = usersRepository.findAll();
        if (dbUsers.isEmpty()) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        // TODO Auto-generated method stub
        return new ResponseEntity<>(dbUsers, HttpStatus.OK);

Define the Repository Class


Let’s define the UsersRepository to get Users from the database. Create class UsersRepository and extend it from the JpaRepository interface. It provides methods for generic CRUD operations.

package com.manytomanyrelationship.repository;

import com.manytomanyrelationship.domain.Users;
import org.springframework.stereotype.Repository;

public interface UsersRepository extends JpaRepository<Users, Integer> { 


Build and Run the Application

Now it’s time to compile the code, run the application and see JPA Hibernate in action. Now go to the database, and you’ll see the three tables. Because the property of creating the DDL is set to true, the tables are generated automatically.


For testing, let’s add a few records to our main Spring Boot Application class.

package com.manytomanyrelationship;

import com.manytomanyrelationship.domain.Role;
import com.manytomanyrelationship.domain.Users;
import com.manytomanyrelationship.repository.UsersRepository;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class DemoApplication {

    static final Logger logger = LogManager.getLogger(DemoApplication.class);

    public static void main(String[] args) {
        ApplicationContext context =, args);"hello!!");
        UsersRepository usersRepository = context.getBean(UsersRepository.class);;;

    private static Users createUserObject1() {
        Users user = new Users();

        Role role = new Role();
        role.setName("Lab Staff");
        List<Role> roles = Collections.singletonList(role);
        return user;

    private static Users createUserObject2() {
        Users user = new Users();

        Role role1 = new Role();

        Role role2 = new Role();
        List<Role> roles = new ArrayList<>();
        return user;

We have saved two User records using UsersRepository, and from the console, we observe the order of persistence of records. Firstly, the data is entered into the Users table. Secondly, the Role table’s records are inserted. Finally, the data in the user_roles table are populated with the relevant primary keys. Here is a  snapshot of console logs for better understanding:

We can now test the REST API that we have exposed.

Many to Many relationship in Spring Boot and JPA

Please notice that we have provided the password in plain text for simplicity. The best practice is not to store passwords in plain text and not to return them in plain text in the HTTP Response, especially in the Production Environment, as this is not secure.  To discover how to encrypt user’s password using Spring Framework, read this article.


This article has covered how to implement a Uni-directional Many to Many Relationship with JPA in a Spring Boot Application. If you find this article helpful, don’t forget to share your feedback or thoughts in the comments section.

If you want to learn more about the Spring Boot articles, stay tuned for some exciting stuff coming ahead!

Happy Coding!

Leave a Reply

Your email address will not be published.