First let me say that if you have gotten to this point successfully, congrats! and thumbs up to you! You’ll sure be an expert if you keep this pace and don’t give up!
We would continue with the Hibernate Relationship tutorial. We’ll cover the following:
- Part 1 to 7 – Setting Up
- Part 8 – @JoinColumn Annotation
- Part 9 – Setup findAll() and findById() for all Entities
- Part 10 – Infinite Recursion(StackOverflow Error)
- Part 11 – Handling Infinite Recursion Using JsonManagedReference and JsonBackReference
- Part 12 – JsonIgnore and JsonIdentityInfo
- Part 13 to 16 – Retrieving Child Records
- Part 17 to 20 – Inserting New Records. Using REST Client
- Part 21 to 28 – Deleting, CascadeTypes and FetchTypes
Pay attention to how to solve the problem of Infinite recursion.
Part 8 – @JoinColumn Annotation
The @JoinColumn annotation is used to specify the actual column(in the table) used for the mapping. This is done at the entity that owns the mapping.
In the case of User-Post relationship, the Post owns the relationship and automatically creates the user_id column. This is the JoinColumn.
Similarly, the Location-User relationship, the Location owns the relationship and provides the location_id column.
Follow the steps below to add the @JoinColumn annotation
Step 1: In the Location field of the User entity, add @JoinColumn(name=”location_id”)
Step 2: In the User field of the Post entity, add @JoinColumn(name=”user_id”)
Step 3: Relaunch and check the tables in the h2 console (nothing changes though!)
Part 9 – Setup findAll() and findById() for all Entities
Write the methods to in the RestController files for Post, User and Location.
(You should be able to do this by now, else, watch the video and follow along)
The three RestController and Services files would contain the following:
UserController
@Autowired private UserService userService; @GetMapping("/users") public List<User> getAllUsers() { return userService.findAll(); } @GetMapping("/users/{id}") public Optional<User> getUserById(@PathVariable Integer id) { return userService.findById(id); }
UserService
@Autowired private UserRepository userRepository; public List<User> getAllUsers() { return (List<User>) userRepository.findAll(); } public Optional<User> getUserById(Integer id) { return userRepository.findById(id); }
Step 1: Launch the application and visit http://localhost/users to see the list of users.
LocationController
@Autowired private LocationService locationService; @GetMapping("/locations") public List<Location> getAllLocations() { return locationService.findAll(); } @GetMapping("/locations/{id}") public Optional<Location> getLocationById(@PathVariable Integer id) { return locationService.findById(id); }
LocationService
@Autowired private LocationRepository locationRepository; public List<Location> findAll() { return (List<Location>) locationRepository.findAll(); } public Optional<Location> findById(Integer id) { return locationRepository.findById(id); }
PostController
@Autowired private PostService postService; @GetMapping("/posts") public List<Post> getAllPosts() { return postService.findAll(); } @GetMapping("/posts/{id}") public Optional<Post> getPostById(@PathVariable Integer id) { return postService.findById(id); }
PostService
private PostRepository postRepository; public List<Post> findAll() { return (List<Post>) postRepository.findAll(); } public Optional<Post> findById(Integer id) { return postRepository.findById(id); }
Part 10 – Infinite Recursion (StackOverflow Error)
We would now solve a problem that always arises when you have mapping between entities. Let’s see what the problem is first!
Step 1: In the User entity, right-click and generate Getter and Setters for the posts field
Step 2: In the Location entity, right-click and generate Getter and Setter for the users field
Step 3: Relaunch the application. Try to access the list of users via http://localhost:8080/users. You will notice, that it produces an infinite number of items. In you look at the console, you will now see this error.
Let’s solve it!
Part 11- Solving Infinite Recursion using @JsonManagedReference and @JsonBackReference
So we need a way to break the infinite recursion loop. The @JsonManagedReference is used on the OneToMany side while the @JsonBackReference is used at the @ManyToOne side.
@JsonManagedReference is the forward part of the mapping/reference and the data gets serialized normally.
@JsonBackReference is is the backward side of the mapping and the data does not get serialized
Follow the steps below:
Step 1: Add @JsonManagedReference to the getPosts method in the User entity
Step 2: Add @JsonBackReference to the getUser method of the Post entity
Step 3: Add @JsonManagedReference to the getUsers method of the Location entity
Step 4: Add @JsonBackReference to the getLocation method of the User entity
Step 5: Relaunch the application, try to access list of Users, Locations, or Posts. Notice that the problem is solved
Other methods of handling this problem include use of @JsonIdentityInfo and JsonIgnore annotations. These are discussed below
Part 12 – @JsonIdentifyInfo and @JsonIgnore
Now, the @JsonIgnore is an alternative for the @JsonBackReference. So you can used @JsonIgnore in place of @JsonBackReference
@JsonIdentityInfo can be used in place of the both @JsonManagedReference and @JsonBackReference. However, the @JsonIdentityInfo annotation is added to the class and NOT to the methods. Also, the @JsonIdentityInfo requires some attributes as shown in the code below:
@JsonIdentityInfo( generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
If you have gotten to this point successfully, congrats! and thumbs up to you! You’ll sure be an expert if you keep this pace and don’t give up. Feel free to watch the videos and if you have challenges, mention it in the comment box either below this page or below the video.
Now, on to the next Part!
4 thoughts on “Hibernate Relationship Tutorial – @OneToMany and @ManyToOne (Part 8 to 12)”