6

I am trying to get Json String from Mono. I tried to use block() method to get object it worked fine , but when I use map/flatmap ,I don't see following lines of code is executed.And I see account Mono is not empty.

private String getJsonString( Mono<Account> account) {
        response.map(it->{
           **// call is not coming here** 
            val json = mapper.writeValueAsString(it)
            System.out.println(son)
        });
    }

am I doing anything wrong here?

Rocky4Ever
  • 828
  • 3
  • 12
  • 35
  • The pipeline isn't executed until someone asks for the result; the `map` is lazy. – chrylis -cautiouslyoptimistic- Jul 31 '20 at 01:11
  • how can get the json from mono then?I am trying to call another method which uses json string to insert into db .I used subscribe() but that wroks some time fails most of the time.And also tried to use flatmap same issue method is not being called. – Rocky4Ever Jul 31 '20 at 01:13
  • _Usually_ the approach is that the other method should take a `Mono jsonString`. If it is completely impossible to do that (for example, you're using a database that doesn't have a reactive driver), then you'll need to call `block()` to "exit" the reactive context and retrieve your value. (I think that what you mean by "fails most of the time" is simply that you were outputting from inside the pipeline and didn't always see it. If you'd put a `sleep` in the place you called `subscribe()` and given it time to run, you'd probably have seen it.) – chrylis -cautiouslyoptimistic- Jul 31 '20 at 01:17
  • but when i use flatMap in my controller to call handler method it goes service method with Object not mono?serviceRequest-->Mono-->Object how this works? – Rocky4Ever Jul 31 '20 at 01:22
  • sorry "handle"-->service method – Rocky4Ever Jul 31 '20 at 01:27
  • 2
    If possible, your service should be refactored to accept a `Mono`. If that is not possible, you have to call `block()` and pass the result. (`block()` interrupts the reactive processing, so it is less efficient than passing a `Mono` or `Flux`, but if you must work with non-reactive services, then that's what you do.) – chrylis -cautiouslyoptimistic- Jul 31 '20 at 02:34

1 Answers1

4

If you give a read to the official documentation , you will see that:

Nothing happens until you subscribe

Now to understand, In spring boot webflux based microservice, who is the subscriber?, have a look at this stackoverflow question

Now, if you think, you can have blocking and reactive implementations in the same service, unfortunately, it doesn't work like that. For this you have to understand the event loop model on which reactor works. Thus calling a block method at any point in the flow is of no good and is equivalent to using the old blocking spring-web methods. Because the thread in which the request is being processed gets blocked and waits for the outcome of the I/O operation / network call.

Coming to your question in the comment:

But when i use flatMap in my controller to call handler method it goes service method with Object not mono?serviceRequest-->Mono-->Object how this works?

Let me give you a simple example for this:

Suppose you have an employee application, where you want to fetch details of an employee for a given id. Now in your controller, you will have an endpoint like this:

@GetMapping("/{tenant}/api/employee/{id}")
  public Mono<ResponseEntity> getEmployeeDetails(@PathVariable("id") Long employeeId) {
    return employeeService.getDetails(employeeId)
        .map(ResponseEntity::ok);
  }

Now in your service,

  public Mono<EmployeeEntity> getDetails(Long employeeId) {
    return employeeRepository.findById(employeeId);
  }

And your repository will look like this:

@Repository
public interface EmployeeRepository extends ReactiveCrudRepository<EmployeeEntity, Long> {

}
Abhinaba Chakraborty
  • 3,488
  • 2
  • 16
  • 37