Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JpaRepository findAll returns empty List

findAll() method from JpaRepository returns empty value, but correct number of empty values

I'm using h2 database and everything has worked fine until some unknown moment. Simple GET at http://localhost:8080/users returns {} x number of users previously added to the database. I tried implementing a method that would return id based on username and that works just fine.

Here is my User.java:

@Entity
@Table(name = "Users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "username")
    @NotBlank(message = "Username is mandatory")
    @Size(min = 1, max = 20, message = "Username must be less than 20 characters long")
    private String username;
    @Column(name = "balance")
    private Double balance = 0.0;

    Long getId() {
        return id;
    }

    void setId(Long id) {
        this.id = id;
    }

    String getUsername() {
        return username;
    }

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

    Double getBalance() {
        return balance;
    }

    void setBalance(Double balance) {
        this.balance = balance;
    }
}

Here is UserService which implements methods from IUserService:

@Service
public class UserService implements IUserService {

    @Autowired
    private UserRepository repository;

    @Override
    public void createNewUser(User user) {
        repository.save(user);
    }

    @Override
    public List<User> findAll() {
        return repository.findAll();
    }

    @Override
    public Long findByUsername(String username) {
        return repository.findByUsername(username);
    }

    @Override
    public User findById(Long id) {
        return repository.findById(id).orElse(null);
    }

    @Override
    public boolean checkIfUsernameIsTaken(User user) {
        return repository.findByUsername(user.getUsername()) != null;
    }

    @Override
    public void deleteUser(Long id) {
        repository.deleteById(id);
    }

    @Override
    public void updateBalance(Long id, Double balance) {
        repository.updateBalance(id, balance);
    }
}

I tried with and without @Column annotations and it doesn't seem to do anything.

The output I get from Postman is [{}] if I added only one user via createNewuser(), [{},{}] if I added two users and so on. I don't understand what broke the findAll() method.

P.S. updateBalance() doesn't work either, but that's for some other time.

Edit: some ov you asked for UserController:

@RestController
public class UserController {

    @Autowired
    IUserService userService;

    @GetMapping("/users")
    public List<User> findUsers() {
        return userService.findAll();
    }

    @GetMapping("/users/{id}")
    public User findUserById(@PathVariable Long id) {
        return userService.findById(id);
    }

    @PostMapping("/users")
    public ResponseEntity<Object> createUser(@RequestBody User user) {

        if (userService.checkIfUsernameIsTaken(user)) {

            Map<String, Object> response = new HashMap<>();
            response.put("status", HttpStatus.NOT_ACCEPTABLE);
            response.put("errors", "Username is already taken");
            response.put("timestamp", new Date());

            return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
        } else {
            userService.createNewUser(user);
            User currentUser = userService.findById(userService.findByUsername(user.getUsername()));
            Map<String, Object> response = new HashMap<>();
            response.put("id", currentUser.getId());
            response.put("username", currentUser.getUsername());
            response.put("balance", currentUser.getBalance());
            return new ResponseEntity<>(response, HttpStatus.OK);
        }
    }

    @DeleteMapping("/users/{id}")
    public void deleteUser(@PathVariable Long id) {
        userService.deleteUser(id);
    }

    @PutMapping("/users/{id}/{balance}")
    public void updateBalance(@PathVariable Long id, @PathVariable Double balance) {
        userService.updateBalance(id, balance);
    }
}

and UserRepository:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {

    @Query("SELECT id FROM User WHERE username = ?1")
    Long findByUsername(String username);

    @Transactional
    @Modifying
    @Query("UPDATE User SET balance = ?2 WHERE id = ?1")
    void updateBalance(Long id, Double balance);
}

My problems first appeared (or so I think) after I implmented the update query, but I tried running a version where I know it worked on a different computer, but it didn't work.

like image 507
Filip Pranklin Avatar asked May 30 '19 02:05

Filip Pranklin


People also ask

What does findAll return in JPA?

findAll() would return empty.

Does JPA findAll return null?

findAll. Returns all entities matching the given Specification and Sort . Parameters: spec - can be null.

What does the findAll method returns in spring JPA?

The List<Todo> findAll() method returns all Todo objects that are found from the database. The Optional<Todo> findOne(Long id) method finds the todo entry whose id is given as a method parameter.


Video Answer


2 Answers

The problem is that your properties are not mutable. You have exposed getters and setters but you didn't specify access level, and they are not public by default, so hibernate can not see them and hence can not populate your entity with the record returned from the database. Making them public should resolve the issue.

like image 114
NiVeR Avatar answered Oct 09 '22 13:10

NiVeR


Although the answer above fixes the issue, I have encountered a similar situation where repository.findById(id) would return a result and repository.findAll() would return empty.

It turns out that I had wrapped the caller method with @Transactional(readOnly = true), where the method would write and then read all records:

@Override
    @Transactional(readOnly = true)
    public List<Object> writeThenReadAll(...){
       repository.save(...);
       ...
       Object byId = repository.findById(1L).get(); //not null
       List<Object> all = repository.findAll(); //returns empty
       return all;
    }

changing @Transactional(readOnly = true) to @Transactional(readOnly = false) fixed the issue.

like image 2
user3582348 Avatar answered Oct 09 '22 12:10

user3582348