user2911332
user2911332

Reputation:

Consuming a Mono<T> in a Spring web Controller

I'm currently trying to understand Reactor and refactored a service method that returned an Optional<CompanyDetails> to use Reactor's Mono<CompanyDetails> instead:

public Mono<CompanyDetails> findOne(String id) {
    CompanyDetails result = retrieveFromSomewhere(id);
    return Mono.justOrEmpty(result);
}

From my understanding this should emit either empty() or just(result). I consume the service in a Spring web Controller like that:

@RequestMapping(value = "{id}", method = RequestMethod.GET)
public DeferredResult<CompanyDetails> getCompany(@PathVariable String id) {
    final DeferredResult<CompanyDetails> result = new DeferredResult<>();
    companyService.findOne(id)
            .consume(result::setResult);
    return result;
}

This works fine if a result was found, but if findOne emits empty() it runs into a timeout. I could call get() explicitly and check for null, but that feels totally wrong.

Also: Before refactoring, getCompany threw a NotFoundException if no result was found, is that possible at all, or am I on the wrong track entirely?

Upvotes: 4

Views: 1596

Answers (1)

user2911332
user2911332

Reputation:

Found the answer myself: First it turned out that Reactor's Mono has a toCompletableFuture-method and Spring MVC can also use that instead of DeferredResult. Failing the CompletableFuture throws an Exception just as expected.

To fail, Mono has to emit an error instead of empty:

public Mono<CompanyDetails> findOne(String id) {
    CompanyDetails result = retrieveFromSomewhere(id);
    return Mono
            .justOrEmpty(result)
            .otherwiseIfEmpty(Mono.error(...));
}

@RequestMapping(value = "{id}", method = RequestMethod.GET)
public CompletableFuture<CompanyDetails> getCompany(@PathVariable String id) {
    return companyService.findOne(id)
            .toCompletableFuture();
}

Much better now.

Upvotes: 3

Related Questions