javaspring-webfluxproject-reactor

Mono continue if not present


Given two sessions (A & B) as strings, my goal is to check if A is valid in the database. If A exists, return it. If A is not provided (or does not exist in the database), I would like to proceed with checking session B in the database.

The problem with my code below is that I return regardless whether A has been found or not. Instead, I would like to check that if A is not found (is empty), proceed with checking B. Is there a way to check if a Mono does not exist?

String sessionA = "1";
String sessionB = "2";


public Mono<Session> getSession() {
    if (!StringUtils.isEmpty(sessionA)) {
        return myDatabaseService.findByKeyOne(sessionA); // Should only return if it exists, otherwise, check session B
    }

    if (!StringUtils.isEmpty(sessionB)) {
        return myDatabaseService.findByAnotherSession(sessionB);
    }

    throw new Exception(); // If both sessions have not been found
}


// My Database Service (dummy code)
public Mono<Session> findByKeyOne(String session) {
    try {
        return myDatabase.find(); 
    } catch (Exception e) { 
        return Mono.empty() // If an error occurrd or no result has been found, return empty
    }
}

Solution

  • Expanding on @Eugene Botyanovsky's answer with addressing the optional sessionA, you may try something like this:

    // Return an exception in case both sessionA and sessionB are empty.
    if (StringUtils.isEmpty(sessionA) && StringUtils.isEmpty(sessionB)) {
      return Mono.error(new Exception());
    }
    
    // simply return an empty Mono if sessionA is empty.
    Mono<Session> sessionAMono = StringUtils.isEmpty(sessionA) 
                                ? Mono.empty() 
                                : myDatabaseService.findByKeyOne(sessionA);
    
    return sessionAMono
             .switchIfEmpty(Mono.defer(() -> myDatabaseService.findByAnotherSession(sessionB)));
    

    In this case, both scenarios when sessionA is empty, as well as when myDatabaseService.findByKeyOne(sessionA) returns an empty result (assuming that it does).

    Edit:
    Unrelated to your concern but I wanted to point out in your findByKeyOne function, since the myDatabase.find() is returning a Mono, wrapping it with try catch won't work since it's asynchronous. Which means you'll need to handle any potential error in the same stream. You can do something like:

    return myDatabase.find()
                .onErrorResume(throwable -> Mono.empty();