Pass Mono to the last map

Viewed 38

I'm trying to make this code reactive, but without any luck.

This is the old code:

public BookInfo get( int libraryId )
{
    Optional<Book> optionalBook = bookRepository.findByLibraryId( bookId );

    int bookId = optionalBook
        .map( b -> b.id() + 1 )
        .orElse( 0 );
    
    return bookRepository.findById( bookId )
                         .map( pages -> new BookInfo( optionalBook, pages ) );
}

This is what I came up with so far:

public Mono<BookInfo> get( int libraryId )
{
    return bookRepository.findByLibraryId( bookId )
                         .flatMap( book -> bookRepository.findById( book.id() ) )
                         .switchIfEmpty( Mono.defer( () -> bookRepository.findById( 0 ) ) )
                         .map( pages -> new BookInfo( null, pages ) );
}

This issue is how can I get the book returned by the findByLibraryId method to the last map?

For this case I only need to pass in an extra value to the last map but what if I have to pass multiples?

Thanks

1 Answers

In functional libraries like Reactor you can pass arguments from previous steps by nesting. In your case you can achieve this by calling map inside the flatMap.

Here are two examples of doing this. Both are equivalent so choose the one by your own preference:

Code block 1: map at both Monos

public Mono<BookInfo> get(int bookId) {
    return bookRepository.findByLibraryId(bookId)
            .flatMap(book -> bookRepository.findById(book.id() + 1)
                    .map(pages -> new BookInfo(Optional.of(book), pages)))
            .switchIfEmpty(Mono.defer(() -> bookRepository.findById(0)
                    .map(pages -> new BookInfo(Optional.empty(), pages))));
}

Code block 2: map at one Mono by first mapping to an Optional

public Mono<BookInfo> get2(int bookId) {
    return bookRepository.findByLibraryId(bookId)
            .map(Optional::of)
            .defaultIfEmpty(Optional.empty())
            .flatMap(optionalBook -> bookRepository.findById(
                            optionalBook.map(book -> book.id() + 1).orElse(0))
                    .map(pages -> new BookInfo(optionalBook, pages)));
}

Note that in both cases, the map has access to book/optionalBook.

Related