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.