Mono.zip with null

Viewed 1907

My code:

Mono.zip(
            credentialService.getCredentials(connect.getACredentialsId()),
            credentialService.getCredentials(connect.getBCredentialsId())
)
.flatMap(...

From the frontend we get connect object with 2 fields:

connect{
aCredentialsId : UUID //required
bCredentialsId : UUID //optional
}

So sometimes the second line credentialService.getCredentials(connect.getBCredentialsId())) can return Mono.empty

How to write code to be prepared for this empty Mono when my second field bCredentialsId is null?

What should I do? In case of empty values return Mono.just(new Object) and then check if obj.getValue != null??? I need to fetch data from DB for 2 different values

3 Answers

The strategy I prefer here is to declare an optional() utility method like so:

public class Utils {

    public static <T> Mono<Optional<T>> optional(Mono<T> in) {
        return in.map(Optional::of).switchIfEmpty(Mono.just(Optional.empty()));
    }

}

...which then allows you to transform your second Mono to one that will always return an optional, and thus do something like:

Mono.zip(
        credentialService.getCredentials(connect.getACredentialsId()),
        credentialService.getCredentials(connect.getBCredentialsId()).transform(Utils::optional)
).map(e -> new Connect(e.getT1(), e.getT2()))

(...assuming you have a Connect object that takes an Optional as the second parameter of course.)

An easier way is using mono's defaultIfEmpty method.

Mono<String> m1 = credentialService.getCredentials(connect.getACredentialsId());
Mono<String> m2 = credentialService.getCredentials(connect.getBCredentialsId()).defaultIfEmpty("");

Mono.zip(m1, m2).map(t -> connectService.connect(t.getT1(), t.getT2()));

Explanation: if m2 is null then get empty string as a default value instead of null.

Instead of using .zip here, I would work with a nullable property of Connect and use .flatMap in combination with .switchIfEmpty for it.

Kotlin-Version:

val aCredentials = credentialService.getCredentials(connect.getACredentialsId())

credentialService.getCredentials(connect.getBCredentialsId())
       .flatMap { bCredentials -> aCredentials
                      .map { Connect(it, bCredentials)}
                      .switchIfEmpty(Connect(null, bCredentials)) 
        }
       .switchIfEmpty { aCredentials.map { Connect(it, null) } }
Related