JpaRepository findAll returns empty List
Solution 1
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.
Solution 2
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.
Filip Pranklin
Currently I am employed as an Android Developer and I'm also a student at FER.
Updated on June 13, 2022Comments
-
Filip Pranklin almost 2 years
findAll()
method fromJpaRepository
returns empty value, but correct number of empty valuesI'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 fromIUserService
:@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 thefindAll()
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.
-
Jebil almost 5 yearsHibernate as well as HttpMessageConverters cannot see the properties that's why
{ }
is returned, Otherwise{ "id" : null , "username" : null}
would have returned. So making Getters and Setterspublic
in the entity class should solve this issue -
Jebil almost 5 yearsof-course, you mentioned Hibernate , I just added the reason for empty json object too
-
Filip Pranklin almost 5 yearsThank you! The IDE(IntelliJ Idea) suggested that getters and setters could be package-private so I made them package-private.
-
NiVeR almost 5 yearsOften, IntelliJ, tries to be smarter than it actually is :)
-
Jay Teli about 2 yearsThanks. In the Entity class , i changed
private int id;
topublic int id;
and now i am getting desired response.