I usually have the requirement of generating a Mono/Flux whose values will be generated/calculated on subscription time. For this, both fromCallable and defer operators seem to be fine.
I can't see the difference clearly in the Javadoc:
FromCallable:
public static Mono fromCallable(Callable<? extends T> supplier)
Create a Mono producing its value using the provided Callable. If the Callable resolves to null, the resulting Mono completes empty.
Defer:
public static Mono defer(Supplier<? extends Mono<? extends T>> supplier)
Create a Mono provider that will supply a target Mono to subscribe to for each Subscriber downstream.
Could you explain if both can be used for this requirement and what exact difference there is between them?
Mono.defer is usually used when you already have a Mono from a third-party source, but you want to delay its creation until subscription time because during its creation something is done eagerly.
Consider the following example:
public static void main(String[] args)
{
callExternalService()
.repeat(3)
.subscribe();
}
private static Mono<?> callExternalService()
{
System.out.println("External service is called.");
return Mono.just("result");
}
At first glance, you'd think this example has no issues but when you check the output, you can see that External service is called is only printed once instead of the expected four (one original + three repeats) because it is executed outside of the scope of the returned Mono.
However, if you defer the execution of the Mono, it will be printed four times as expected:
Mono.defer(() -> callExternalService())
.repeat(3)
.subscribe();
Another use case for defer is when you want to test a repeat/retry/re-subscribe logic and you want to have different return values for the mocked service which returns the Mono.
In conclusion, it is indeed very similar to fromCallable, but mostly used when you already have a method which returns a Mono and does something eager. If you have complete control over the code, then you are completely fine with fromCallable.