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.
findAll() would return empty.
findAll. Returns all entities matching the given Specification and Sort . Parameters: spec - can be null.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With