Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

Generic Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this short tutorial, we'll explore various listeners of the Mono object from Spring 5 WebFlux. We'll compare the doOnNext() and doOnSuccess() methods and discover that, even though they're similar, they behave differently for empty Monos.

2. doOnNext

Mono‘s doOnNext() allows us to attach a listener that will be triggered when the data is emitted. For the code examples in this article, we'll use the PaymentService class. In this case, we'll call the processPayment method only when the paymentMono emits the data, using doOnNext():

@Test
void givenAPaymentMono_whenCallingServiceOnNext_thenCallServiceWithPayment() {
    Payment paymentOf100 = new Payment(100);
    Mono<Payment> paymentMono = Mono.just(paymentOf100);

    paymentMono.doOnNext(paymentService::processPayment)
        .block();

    verify(paymentService).processPayment(paymentOf100);
}

However, an empty Mono will not emit any data, and doOnNext will not be triggered. Consequently, if we repeat the test using Mono.empty(), the processPayment method should no longer be called:

@Test
void givenAnEmptyMono_whenCallingServiceOnNext_thenDoNotCallService() {
    Mono<Payment> emptyMono = Mono.empty();

    emptyMono.doOnNext(paymentService::processPayment)
        .block();

    verify(paymentService, never()).processPayment(any());
}

3. doOnSuccess

We can use doOnSuccess to attach a listener that will be triggered when the Mono completes successfully. Let's repeat the test, but using doOnSuccess this time:

@Test
void givenAPaymentMono_whenCallingServiceOnSuccess_thenCallServiceWithPayment() {
    Payment paymentOf100 = new Payment(100);
    Mono<Payment> paymentMono = Mono.just(paymentOf100);

    paymentMono.doOnSuccess(paymentService::processPayment)
        .block();

    verify(paymentService).processPayment(paymentOf100);
}

Though, we should note that a Mono is considered to be completed successfully even if no data is emitted. As a result, for an empty Mono, the code above will call the processPayment method with a null Payment:

Test
void givenAnEmptyMono_whenCallingServiceOnSuccess_thenCallServiceWithNull() {
    Mono<Payment> emptyMono = Mono.empty();

    emptyMono.doOnSuccess(paymentService::processPayment)
        .block();

    verify(paymentService).processPayment(null);
}

4. Conclusion

In this short article, we learned the difference between a Mono‘s doOnNext and doOnSuccess listeners. We saw that we can use doOnNext if we want to react to the data received. On the other hand, we should use doOnSuccess if we want the method call to happen when the Mono completes successfully, regardless of whether it emits data or not.

As always, code from this article can be found over on GitHub.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Generic footer banner
Comments are closed on this article!