How to create Mono?

by coding flower
Creating mono

How to create Mono ?

In this article, I would like to show you several different ways of creating reactive Mono. I'll present how to:

  • create mono without any value
  • create mono with value
  • create mono which contains an exception
  • create eager mono
  • create lazy mono
  • create mono per new subscription

but first, let's start with a short intro about Mono<T> itself.

Mono<T>

In simple words Mono<T> is a customized version of Publisher<T> which is able to emit at most one item.

Create Mono without any value

The most basic version of Mono. This Mono will complete without emitting any item.
Let's test that.

    @Test
    fun `should create empty mono`() {
        val emptyMono = Mono.empty<String>()

        StepVerifier
            .create(emptyMono)
            .expectNextCount(0)
            .verifyComplete()
    }

Create Mono with value

It would be nice to have Mono with some value inside of it, to achieve that we can use just method which accepts any type of data and returns Mono<T>. We can say that we are wrapping given data with Mono.

    @Test
    fun `should create mono with value`() {
        val createdMono = Mono.just("Mono")

        StepVerifier
            .create(createdMono)
            .expectNext("Mono")
            .verifyComplete()
    }

Create Mono which contains exception

Due to the fact that exception exists and we have to deal with them there is also a possibility to create Mono which contains an exception.

    @Test
    fun `should create error mono`() {
        val monoError = Mono.error<RuntimeException> { RuntimeException("Some fishy exception") }

        StepVerifier
            .create(monoError)
            .expectError(RuntimeException::class.java)
            .verify()
    }

Create eager Mono

What does it mean eager Mono? Basically, when we create the Mono we would like to
emit it instantly, during the creation. The method from the second paragraph will do that
for us Mono.just() emits wrapped item at the instantiation time.

    @Test
    fun `mono just is eager`() {
        val atomicInteger = AtomicInteger(0)
        val eagerMono = Mono.just(atomicInteger.incrementAndGet())

        Assertions.assertEquals(1, atomicInteger.get())
    }

Inside the Mono we are incrementing atomicInteger, but we are never subscribing
to given eagerMono, but still, incrementation takes place.

Create lazy Mono

Lazy Mono is opposite to the eager Mono, so we are not emitting anything
straight away, we are waiting for a subscription. To achieve that we can use the method
fromCallable which takes Callable as a parameter.

    @Test
    fun `mono from callable is lazy`() {
        val atomicInteger = AtomicInteger(0)
        val lazyMono = Mono.fromCallable { atomicInteger.incrementAndGet() }

        Assertions.assertEquals(0, atomicInteger.get())
    }

Inside the Mono we are incrementing atomicInteger, but we are never subscribing
to lazeMono and incrementation doesn't take a place. To execute
atomicInteger.incrementAntGet() we have to subscribe lazyMono.

Create new Mono per each subscription

Method Mono.defer() will create a provider that will deliver the given Mono for each
subscriber. Let's analyze the example below.

    @Test
    fun `mono defer` () {
        val atomicInteger = AtomicInteger(0)

        val deferedMono = Mono.defer { Mono.just(atomicInteger.incrementAndGet()) }

        StepVerifier
            .create(deferedMono)
            .expectNext(1)
            .verifyComplete()

        StepVerifier
            .create(deferedMono)
            .expectNext(2)
            .verifyComplete()
    }

We are doing two subscriptions on the same deferedMono provider. The result is quite
simple to predict, each subscription executes incrementation emitted by Mono.just()
delivered by Mono.defer() creator.

Related Posts

Leave a Comment

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More