Not able to fetch other entity using @OneToMany relationship in Spring

Viewed 99

User.java

package com.example.accessingdatamysql.entities;


import javax.persistence.*;
import java.util.List;
import java.util.Objects;

@Entity
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String firstName;

    private String lastName;

    private String email;

    @ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    @JoinColumn(name = "book_id")
    private Book book;

    public User() {
    }

    Getters/Setters

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", email='" + email + '\'' +
                ", book=" + book +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id) && Objects.equals(firstName, user.firstName)
                && Objects.equals(lastName, user.lastName) && Objects.equals(email, user.email);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, firstName, lastName, email);
    }
}

Book.java

package com.example.accessingdatamysql.entities;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    private int numberOfPages;

    private String author;

    @OneToMany(mappedBy = "book", cascade = CascadeType.ALL)
    private List<User> users = new ArrayList<>();

    public Book() {
    }

    Getters/Setters

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", numberOfPages=" + numberOfPages +
                ", author='" + author + '\'' +
                '}';
    }
}

UserService.java

package com.example.accessingdatamysql.services;

import com.example.accessingdatamysql.entities.Book;
import com.example.accessingdatamysql.entities.User;
import com.example.accessingdatamysql.repositories.BookRepository;
import com.example.accessingdatamysql.repositories.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class UserService {

    private final String USER_EXISTS_ERROR = "user with id %s already exists";

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private BookRepository bookRepository;

    public User addUser(User user) {
        userRepository.findByEmail(user.getEmail()).ifPresent(param -> {
            throw new IllegalStateException(String.format(USER_EXISTS_ERROR, user.getEmail()));
        });

        Book book = bookRepository.findByName(user.getBook().getName()).orElse(null);

        if(null == book) {
            book = new Book();
        }

        book.setName(user.getBook().getName());
        book.setAuthor(user.getBook().getAuthor());
        book.setNumberOfPages(user.getBook().getNumberOfPages());

        user.setBook(book);
        user.setFirstName(user.getFirstName());
        user.setLastName(user.getLastName());
        user.setEmail(user.getEmail());

        return userRepository.save(user);
    }

    public List<User> getUsers() {
        return userRepository.findAll();
    }

    public User getUser(Integer id) {
        return userRepository.findById(id).orElseThrow(() -> new IllegalStateException("User not found"));
    }

    public User updateUser(Integer id, User user) {
        userRepository.findById(id).orElseThrow(() -> new IllegalStateException(("")));
        user.setId(id);
        userRepository.save(user);
        return user;
    }

    public void removeUser(Integer id) {
        userRepository.findById(id).orElseThrow(() -> new IllegalStateException(""));
        userRepository.deleteById(id);
    }
}

UserController.java

package com.example.accessingdatamysql.controllers;

import com.example.accessingdatamysql.entities.User;
import com.example.accessingdatamysql.repositories.UserRepository;
import com.example.accessingdatamysql.services.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;


@RestController
public class UserController {

    @Autowired
    private UserService userService;

    @PostMapping(path = "/users")
    public User addNewUser(@RequestBody User user) {
        return userService.addUser(user);
    }

    @GetMapping(path = "/users")
    public  Iterable<User> getAllUsers() {
        return userService.getUsers();
    }

    @GetMapping(path = "/users/{id}")
    public  User getUser(@PathVariable Integer id) {
        return userService.getUser(id);

    }

    @PutMapping("/users/{id}")
    public User updateUser(@RequestBody User newUser, @PathVariable Integer id) {
        return userService.updateUser(id, newUser);
    }

    @DeleteMapping("/users/{id}")
    public void deleteUserById(@PathVariable Integer id) {
        userService.removeUser(id);
    }
}

Error

java.lang.NullPointerException: Cannot invoke "com.example.accessingdatamysql.entities.Book.getName()" because the return value of "com.example.accessingdatamysql.entities.User.getBook()" is null
    at com.example.accessingdatamysql.services.UserService.addUser(UserService.java:29) ~[classes/:na]
at com.example.accessingdatamysql.controllers.UserController.addNewUser(UserController.java:18) ~[classes/:na]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:681) ~[tomcat-embed-core-9.0.60.jar:4.0.FR]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.60.jar:4.0.FR]

http://localhost:8080/users - POST

{
        "firstName": "Smith",
        "lastName": "Smithy",
        "email": "smithy12@gmail.com",
        "books": [
            {
                "name" : "Effective Spring",
                "numberOfPages" : "366",
                "author" : "John"
            }
        ]
    }

Book table User table

Hello, I'm working on my first CRUD application and I wanted to implement @OneToMany relationship, where each book have multiple users. I'm trying to get it working for a few days already, but with a little success. I'm not able to POST, every other mapping works fine. There's also a problem with assigning user/book to book/user. When I use GET all I get is

{
        "id": 23,
        "firstName": "Will",
        "lastName": "Lucky",
        "email": "wlucky@gmail.com",
        "book": null
    }

And the same is for books

{
        "id": 25,
        "name": "Effective Spring",
        "numberOfPages": 366,
        "author": "Dantes",
        "users": []
    }

I know that I'm doing something wrong here, but I can't figure it out and I need your help, please. I'm pretty new to Spring, so don't be too harsh on me, as I'm still in the learning process.

1 Answers

By default hibernate fetch type is lazy,

Change the Book entity to the following code,

@Entity
public class Book {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;

    private int numberOfPages;

    private String author;

    @OneToMany(mappedBy = "book", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    private List<User> users = new ArrayList<>();

    public Book() {
    }

    Getters/Setters

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", numberOfPages=" + numberOfPages +
                ", author='" + author + '\'' +
                '}';
    }
}

But this is not the right way to solve this problem, please check out this link

Related