Accepted answer
it's because switchifempty accepts mono "by value". meaning that even before you subscribe to your mono, this alternative mono's evaluation is already triggered.
imagine a method like this:
mono<string> asyncalternative() {
return mono.fromfuture(completablefuture.supplyasync(() -> {
system.out.println("hi there");
return "alternative";
if you define your code like this:
mono<string> result = mono.just("some payload").switchifempty(asyncalternative());
it'll always trigger alternative no matter what during stream construction. to address this you can defer evaluation of a second mono by using mono.defer
mono<string> result = mono.just("some payload")
.switchifempty(mono.defer(() -> asyncalternative()));
this way it will only print "hi there" when alternative is requested
elaborating a little on my answer. the problem you're facing is not related to reactor but to java language itself and how it resolves method parameters. let's examine the code from the first example i provided.
mono<string> result = mono.just("some payload").switchifempty(asyncalternative());
we can rewrite this into:
mono<string> firstmono = mono.just("some payload");
mono<string> alternativemono = asyncalternative();
mono<string> result = firstmono.switchifempty(alternativemono);
these two code snippets are semantically equivalent. we can continue unwrapping them to see where the problem lies:
mono<string> firstmono = mono.just("some payload");
completablefuture<string> alternativepromise = completablefuture.supplyasync(() -> {
system.out.println("hi there");
return "alternative";
}); // future computation already tiggered
mono<string> alternativemono = mono.fromfuture(alternativepromise);
mono<string> result = firstmono.switchifempty(alternativemono);
as you can see future computation was already triggered at the point when we start composing our mono
types. to prevent unwanted computations we can wrap our future into a defered evaluation:
mono<string> result = mono.just("some payload")
.switchifempty(mono.defer(() -> asyncalternative()));
which will unwrap into
mono<string> firstmono = mono.just("some payload");
mono<string> alternativemono = mono.defer(() -> mono.fromfuture(completablefuture.supplyasync(() -> {
system.out.println("hi there");
return "alternative";
}))); // future computation defered
mono<string> result = firstmono.switchifempty(alternativemono);
in second example the future is trapped in a lazy supplier and is scheduled for execution only when it will be requested.
for those who, despite the well voted answer, do not still understand why such a behaviour:
reactor sources (mono.xxx & flux.xxx) are either:
lazily evaluated : the content of the source is evaluated/triggered only when a subscriber subscribes to it;
or eagerly evaluated : the content of the source is immediately evaluated even before the subscriber subscribes.
expressions like mono.just(xxx)
, flux.just(xxx)
, flux.fromiterable(x,y,z)
are eager.
by using defer()
, you force the source to be lazily evaluated. that's why the accepted answer works.
so doing this:
somemethodreturningamono()
.switchifempty(builderror());
with builderror()
relying on an eager source to create an alternative mono will always be evaluated before the subscription:
mono<string> builderror(){
return mono.just("an error occured!"); //<-- evaluated as soon as read
to prevent that, do this:
somemethodreturningamono()
.switchifempty(mono.defer(() -> builderror()));
read this answer for more.
Mono switchIfEmpty() is always called
Mono - All the doOnError handlers are getting called
Is a specific @RequestMapping always called in favour of a variable @RequestMapping in Spring
Http-Get-Function seems to be called multiple times in one call and always returns an empty array
Why does my Spring Boot App always shutdown immediately after starting?
Why do I always get 403 when fetching data with RestTemplate?
Mono class in Java: what is, and when to use?
Spring Webflux and @Cacheable - proper way of caching result of Mono / Flux type
Access is Always Denied in Spring Security - DenyAllPermissionEvaluator
Spring Boot MVC Test - MockMvc is always null
Get API response error message using Web Client Mono in Spring Boot
Spring 5 WebFlux Mono and Flux
Spring Boot: @Value returns always null
Why is my spring boot stateless filter being called twice?
Spring Boot : Spring always assigns default value to property despite of it being present in .properties file
How to perform an action only if the Mono is empty and throw an error if not empty
Why does MockMvc always return empty content()?
Scheduled method is called during the tests
Terminated Spring Boot App in Eclipse - Shutdown hook not called
SpringBoot CommandLineRunner run() method not being called
Liquibase: diff always generates indexes
Spring Boot Autowiring Repository Always Null
Spring boot configuration: how to return always same random value when referenced?
Always EOFException with Jacoco exec file
Why spring boot devtools called main method twice?
Spring AOP not working, when the method is called internally within a bean
/tmp/tomcat-docbase is always created with a Spring Boot JAR (but not a WAR)
Why does the main Spring Boot application always trigger PMD's HideUtilityClassConstructorCheck?
Springboot Multi-tenant with MultiTenantConnectionProvider always throw org.apache.tomcat.jdbc.pool.PoolExhaustedException:
Custom Authentication Provider not called when testing spring security with MockMvc
More Query from same tag
Spring boot + Apache CXF for soap web service
How to use Redis command "bitcount" in java
How to load balance among SpringBoot instances
Spring boot data connection is not released
Spring Boot webapp localhost only
Correct way to check for foreign key constraint violation in Hibernate?
Adding my own framework as Dependency And getting errors while starting project
How to persist spring-boot-admin-starter-server service data
ELK : One or more required cgroup files or directories not found: /proc/self/cgroup
com.netflix.zuul.exception.ZuulException: Hystrix Readed time out
Subgraphs in hibernate
Spring Boot: How to run an update query from inside a @scheduled cron method?
Spring Boot ehcache in multi maven project
Feature-Toggle for Spring components
MethodArgumentNotValidException not thrown in case of validation fail
What's wrong with RabbitMQ in Spring Boot
API Spring boot auto redirect to login page
I executed the mybatis update method of the dao layer, but the database is not updated
Setting 'relaxedQueryChars' for embedded Tomcat
Error R10 (Boot timeout) -> Web process failed to bind to $PORT within 90 seconds of launch (Java Discord bot on Heroku)
How to get the effective Properties in Spring Boot application regardless of where it is defined?
Creating generic KafkaTemplate in spring boot Kafka
Keycloak dummy configuration
What is wrong with my HttpURLConnection request?
Java : Merge 2 objects, same properties, multiple level
How to fix Request method 'POST' not supported in Spring Boot?
Test file copy in java
mock resttemplate to test a service as restFul client
Angular application show cors issue and not redirecting to azure ad login page
Exclude specific controllers from sleuth / brave to trace