I'm working on a Spring webflux project using reactive streams. I have a usecase as follows and want to know how can it be done in a reactive way.
@RestController
public class Example {
@GetMapping("/greet")
public Mono<String> Test() {
return Mono.just("Tim")
.map(s -> s.toUpperCase())
.map(s -> s.toLowerCase())
.doOnSuccess(s -> validate(s)) // usecase is to validate here in middle of the pipeline
.onErrorResume(ex -> Mono.just("Guest"))
.map(s -> "Hi, " s);
}
public void validate(String s) {
if(s.length() < 5) {throw new RuntimeException("Name is short");}
}
}
I know this is a contrived example, but I have something similar to this. I thought throwing an error will lead to exception on browser screen when the endpoint is hit. But to my surprise it went to onErrorResume()
and I got Hi, Guest
as response. I thought when throw
is used to throw an exception before the reactive pipeline is assembled, it will not use onErrorResume()
. What am I missing here?
Also coming to question #2, how can I achieve this if I'm using Mono.error(new RuntimeException("Name is short"))
instead of throw new RuntimeException("Name is short")
? Can someone please answer my 2 questions. Suggestions to improve code are appreciated.
CodePudding user response:
I thought when throw is used to throw an exception before the reactive pipeline is assembled, it will not use one rrorResume()
Mono::doOnSuccess
triggers at execution time when the Mono
completes successfully(pipeline is already assembled).
Note that inside intermediate operators like doOnNext
or map
you are free to throw exceptions as Reactor can transform them into proper error signals since at that point a Mono
is already in progress.
how can I achieve this if I'm using Mono.error(new RuntimeException("Name is short")) instead of throw new RuntimeException("Name is short")?
You can replace doOnSuccess
and map
with the handle
operator:
return Mono.just("Tim")
.handle((name, sink) -> {
if(name.length() < 5){
sink.error(new RuntimeException("Name is short"));
} else {
sink.next(name.toLowerCase());
}
})
CodePudding user response:
For the #1 question you can add a predicate in onErrorResume
.onErrorResume(e -> !(e instanceof RuntimeException), ex -> Mono.just("Guest"))
so that you can filter on which error you can return a predefined result.
For question #2 you can replace doOnSuccess
which is a consumer, with flatMap
and return Mono
forvalidate
method:
public Mono<String> Test() {
return Mono.just("Tim")
.map(s -> s.toUpperCase())
.map(s -> s.toLowerCase())
.flatMap(s -> validate(s))
.onErrorResume(e -> !(e instanceof RuntimeException), ex -> Mono.just("Guest"))
.map(s -> "Hi, " s);
}
public Mono<String> validate(String s) {
return (s.length() < 5) ?
Mono.error(() -> new RuntimeException("Name is short")) :
Mono.just(s);
}