Reputation: 42987
I am working on a Spring Boot application. Into a service class I have this service method:
@Override
public User getUserById(Integer userId) {
Optional<User> retrievedUser = this.userRepository.findById(userId);
return retrievedUser.get();
}
As usual it is calling the Spring Data JPA findById() method returning an Optional object.
I am returning the User object. And here I have the following doubt: if the Optional is empty, it is throwing an exception when I this operation is performed:
retrievedUser.get()
So now...what is the most common way to handle situation like this when I have a Optional object.
The previous service method is called into a controller method implementing an API, this one:
@ApiOperation(
value = "Retrieve an user by its id",
notes = "",
produces = "application/json")
@GetMapping(value = "/{useridOrEmail}", produces = "application/json")
public ResponseEntity<User> getUserByIdOrEmail(@PathVariable("useridOrEmail") String userIdOrEmail,
@RequestParam(value="isEmail", required = false, defaultValue = "false") boolean isEmail)
throws NotFoundException {
log.info(String.format("****** Retrieve the user having ID or email: %s *******", userIdOrEmail));
User retrievedUser = null;
if(!isEmail)
retrievedUser = this.userService.getUserById(Integer.parseInt(userIdOrEmail));
else
retrievedUser = this.userService.getUserByemail(userIdOrEmail);
if (retrievedUser == null) {
String ErrMsg = String.format("The user having ID or email %s was not found", userIdOrEmail);
log.warning(ErrMsg);
throw new NotFoundException(ErrMsg);
}
return new ResponseEntity<User>(retrievedUser, HttpStatus.OK);
}
As you can see in my controller method I am checking if the result of the previous service is null, in case an exception will be thrown. This exception is handled by a class extenging ResponseEntityExceptionHandler in such a way to create a proper response.
So my idea was change my service method putting this retrievedUser.get() operation into a try catch. If I obtain the exception my getUserById() service method will return null and so my controller method will thrown the NotFoundException exception that will be handled returning a specific error response by Spring.
Could be a good solution or exist better way to handle situation like this?
Upvotes: 1
Views: 1278
Reputation: 4091
I would return Optionals from the service then you could chain them real nicely like this:
public ResponseEntity<User> getUserByIdOrEmail(@PathVariable("useridOrEmail") String userIdOrEmail,
@RequestParam(value="isEmail", required = false, defaultValue = "false") boolean isEmail)
throws NotFoundException {
log.info(String.format("****** Retrieve the user having ID or email: %s *******", userIdOrEmail));
return fetchUser(userIdOrEmail, isEmail)
.map((user) -> new ResponseEntity<User>(user, HttpStatus.OK))
.orElseThrow(() -> new NotFoundException(String.format("The user having ID or email %s was not found", userIdOrEmail)));
}
private Optional<User> fetchUser(String idOrEmail, boolean isEmail) {
return isEmail
? this.userService.getUserByemail(idOrEmail)
: this.userService.getUserById(Integer.parseInt(idOrEmail));
}
And logging the warning should be handled in a common exception handler which logs all the Not Found's similar way.
Upvotes: 2
Reputation: 2981
A good approach is to accept whatever the database returns. Then the controller should decide what to do:
Optional<User> retrievedUser = isEmail
? this.userService.getUserByemail(userIdOrEmail)
: this.userService.getUserById(Integer.parseInt(userIdOrEmail));
if (!retrievedUser.isPresent()) {
String ErrMsg = String.format("The user having ID or email %s was not found", userIdOrEmail);
log.warning(ErrMsg);
throw new NotFoundException(ErrMsg);
}
return new ResponseEntity<User>(retrievedUser.get(), HttpStatus.OK);
Upvotes: 0