🏠Spring BootSpring Data JPA: @OneToMany Annotation

Spring Data JPA: @OneToMany Annotation

In this post, We will take a look at one to many mapping with spring data jpa. With a simple spring boot application, we will walkthrough through how to implement @OneToMany annotation the right way.

One To Many Relationship mapping

In the object-relational model, the One-To-Many relationship refers to One parent entity that has a correspondence to zero or more child entities. A simple real-world example of this would be between a Branch of a Bank and the Accounts in that branch.

many to one mapping in spring jpa and hibernate

You might see a similar explanation on our Many-To-One relationship using JPA. But you have to understand that the One To Many relationship is nothing but the reverse of Many To One relationship mapping.

Using @OneToMany Annotation in Spring JPA

The @OneToMany annotation is from the java persistence API specification. This annotation represents that a collection of objects are direct children of the current entity. So let us see how this annotation works. For this, We are going to use the same entities from our previous @ManyToOne example.

But with a little twist, we are going to add @OneToMany mapping at the Branch entity.

@Entity
public class Branch {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    Integer id;
    String branchCode;
    String branchName;

    @OneToMany(mappedBy = "branch")
    List<Account> accounts;

    //getters & setters
}
Code language: JavaScript (javascript)

Note that we are using the branch field in the Account entity as the mappedBy value. This lets the JPA implementation know to load all accounts associated with this branch.

I also created a BranchRepository and a BranchController to test out our mapping of One To Many relationships using Spring JPA.

@Repository
public interface BranchRepository extends JpaRepository<Branch, Integer> {

    Branch findBranchById(Integer id);
}Code language: PHP (php)
@Service
public class BranchService {

    private final BranchRepository branchRepository;

    public BranchService(BranchRepository branchRepository) {

        this.branchRepository = branchRepository;
    }

    public Branch getBranch(Integer id) {
        return branchRepository.findBranchById(id);
    }
}
Code language: PHP (php)
@RestController
public class BranchController {

    private final BranchService branchService;

    public BranchController(BranchService branchService) {
        this.branchService = branchService;
    }

    @GetMapping(path = "/branches/{id}")
    public Branch getBranch(@PathVariable("id") Integer id) {
        return branchService.getBranch(id);
    }
}Code language: PHP (php)

When we run the controller and hit “/branches/1” We will not get any results. Instead, you will get an error similar to below.

2021-09-04 22:08:48.159 ERROR 16400 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Infinite recursion (StackOverflowError); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: com.springhow.examples.jpa.domain.entities.Branch["accounts"]->org.hibernate.collection.internal.PersistentBag[0]->com.springhow.examples.jpa.domain.entities.Account["branch"]->com.springhow.examples.jpa.domain.entities.Branch["accounts"]->org.hibernate.collection.internal.PersistentBag[0]->com.springhow.examples.jpa.domain.entities.Account["branch"]->Code language: CSS (css)

This error happens because the JSON serializer responsible for converting objects into JSON format is going into a recursive loop. See that every branch contains a list of Accounts. But Each Account object contains a Branch object. So it expands the fields again and again till it gets a StackOverflowError.

To avoid the infinite recursion problem with one-to-many mapping, you need to add the @JsonBackReference annotation to your @ManyToOne field. This allows the JSON serializer to break the infinite loop.

So let us test this again. Now you can see that the Accounts of the Branch Object is automatically loading in the response.

one to many example using spring jpa

As you see the branch field in Account objects is ignored by the JSON serializer. This gives us a clean approach to work with the responses.

Summary

We learned how to use @OneToMany annotation in Spring JPA with a Spring Boot example. You can check the code at our GitHub repository

Related

Similar Posts

Leave a Reply

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

2 Comments