ichbintobias2
ichbintobias2

Reputation: 33

Spring WebFlux: Perform multiple mappings on the same object?

I'm currently making my first ever reactive project with Spring WebFlux. Unfortunately, I already got a task assigned that I cannot seem to find a solution for. I would like to receive a Mono and perform operations on it, depending on what other Monos complete. My idea goes like this:

private Mono<ResourceModel> setResourcesIfExisting(String resourceName) {
        
        return resourceService.findByFilter(resourceName)
                .flatMap(res -> service1.findByFilter(resourceName).map(res::setResource))
                .flatMap(res -> service2.findByFilter(resourceName).map(res::setResource))
                .flatMap(res -> service3.findByFilter(resourceName).map(res::setResource))
                ;
    }

A Mono will be found by the resourceService, note that this is already the same type that I want to return. But now, I have some other services that deliver resources and in therory there should be exactly one fulfilling resource mono across all of those services. From my tests, it always works if I use one of those flatMaps but as soon as I have two or more consecutively the list that gets collected on the higher level method results empty (I am using the above method for each element of a Flux<String>).

Would someone be able to give me a pointed why this happens? As said above, I barely understand what I'm doing but tried out a lot with no success so far.

Upvotes: 0

Views: 2561

Answers (1)

ashanshamika
ashanshamika

Reputation: 147

The reason for the mentioned output is due to this.

  • Let's assume you gets Mono<ResourceModel> from resourceService.findByFilter(resourceName) which is not empty.
  • But after the first .flatmap by calling service1.findByFilter(resourceName) it may return empty.
  • After returning empty, other flatmap s are not called as no element will be returned as flatmap is called upon each element.

Alternatively you can use the following to achieve what you expected

private Mono<ResourceModel> setResourcesIfExisting(String resourceName) {

    return resourceService.findByFilter(resourceName)
            .flatMap(res -> service1.findByFilter(resourceName)
                    .switchIfEmpty(service2.findByFilter(resourceName))
                    .switchIfEmpty(service3.findByFilter(resourceName))
                    .doOnEach(stringSignal -> res.setResource(stringSignal.get()))
                    .thenReturn(res));
}

thenReturn will return the ResourceModel even if all the service1,2,3 return empty.

Upvotes: 1

Related Questions