2

Is there an operator that allows to process result/success whether or not Mono is empty. For example:

Mono<Bar> result = sourceMono.flatMap(n -> process(n)).switchIfEmpty(process(null));

where:

Mono<Bar> process(Foo in){
Optional<Foo> foo = Optional.ofNullable(in);
...
}

is there a shortcut operator that allows something like below or similar?

Mono<Bar> result = sourceMono.shortCut(process);

More specifically, mono.someOperator() returns Optional<Foo> which would contain null when Mono is empty and have value otherwise.

I wanted to avoid to create process method as mentioned above and just have a block of code but not sure which operator can help without duplicating block.

hmble
  • 140
  • 2
  • 11

2 Answers2

4

There is no built-in operator to do exactly what you want.

As a workaround, you can convert the Mono<Foo> to a Mono<Optional<Foo>> that emits an empty Optional<Foo> rather than completing empty, and then operate on the emitted Optional<Foo>.

For example:

Mono<Bar> result = fooMono            // Mono<Foo>
    .map(Optional::of)                // Mono<Optional<Foo>> that can complete empty
    .defaultIfEmpty(Optional.empty()) // Mono<Optional<Foo>> that emits an empty Optional<Foo> rather than completing empty
    .flatMap(optionalFoo -> process(optionalFoo.orElse(null)));
Phil Clay
  • 4,028
  • 17
  • 22
  • 1
    Great trick !! I could possibly combine it with transformDeffered to make a reusable function/operator....Note: I had to change Optional.empty() to Mono.just(Optional.empty()) as switchIfEmpty expects Mono (perhaps update it to make usable for others). – hmble Jan 23 '20 at 02:51
  • I would assume that's a common scenario for chaining multiple calls, not sure why an Operator was not added. – hmble Jan 23 '20 at 02:54
  • 1
    I edited the answer to use `defaultIfEmpty` (what I intended) instead of `switchIfEmpty` – Phil Clay Jan 23 '20 at 02:56
  • we don't want to introduce anything dealing with `null` unless absolutely necessary, in order to globally discourage null in the API (since the Reactive Streams specification forbids `onNext(null)` – Simon Baslé Jan 24 '20 at 09:06
1

As per above @phil's workaround, here is a reusable function:

private final <T> Mono<Optional<T>> afterSucess(Mono<T> source) {
    return source
       .map(Optional::of) //
       .defaultIfEmpty(Optional.empty());
}

then invoke in publisher line:

Foo<Bar> result = fooMono
    .transformDeferred(this::afterSucess)
    .flatMap(optionalFoo -> process(optionalFoo.orElse(null)));
hmble
  • 140
  • 2
  • 11