I'm trying to convert a project to use Spring WebFlux and am running into a problem getting some basic business logic working. I have a repository layer that is responsible for retrieving / persisting records and a service layer that is responsible for the business rules of the application. What I want to do (in the service) layer is check if a user already exists for the given username. If so, I want to respond with an error. If not, I want to allow the insert to happen.
I call a method on the repository layer that will find a user by username and if not found it will return an empty Mono. This is working as expected; however, I have tried various combinations of flatMap and (defaultIfEmpty and swithIfEmpty) but am unable to get it to compile / build.
public Mono<User> insertUser(User user) {
return userRepository.findByUsername(user.username())
.flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
.switchIfEmpty(userRepository.insertUser(user));
}
The error that I'm getting is that Mono<Object> cannot be converted to Mono<User>
, so the swithIfEmpty
doesn't seem to reflect the appropriate type and casting doesn't seem to work either.
After additional testing, and taking into consideration the responses from my fellow developers, I have landed on the following solution:
public Mono<User> insertUser(User user) {
return userRepository.findByUsername(user.username())
.flatMap(__ -> Mono.error(new DuplicateResourceException("User already exists with username [" + user.username() + "]")))
.switchIfEmpty(Mono.defer(() -> userRepository.insertUser(user)))
.cast(User.class);
}
As Thomas stated, the compiler was getting confused. My assumption is because the flatMap
was returning a Mono with an error and the switchIfEmpty
was returning a Mono with a User so it reverts to a Mono with an Object (hence the additional .cast
operator to get it to compile).
The other addition was to add the Mono.defer
in the switchMap
. Otherwise, the switchIfEmpty
was always firing.
I'm still open to other suggestions / alternatives (since this seems like it would be a fairly common need / pattern).