Fix the rule java:S5411 on Mono/Flux, it leads to worse code

Let’s have a method returning Mono<Boolean> like this:

class MyService {
    public Mono<Boolean> fetchBoolean(int i) {
       ...
    }
}

The code calling the method:

.flatMap(myService::fetchBoolean)
.flatMap(booleanResult -> booleanResult? ... : ...)

Sonar rule java:S5411 (Avoid using boxed “Boolean” types directly in boolean expressions) misreports the usage of primitive boolean and complains.

What it is happy with is an ugly construct like which is much less readable than the original:

.flatMap(myService::fetchBoolean)
.flatMap(booleanResult -> Boolean.TRUE.equals(booleanResult)? ...: ...)

The fact is that Mono and Flux can never carry a null value, so the Boolean prudery here is just misleading and counter-productive.

Suggestion

Do not apply the rule java:S5411 on the parameters of Mono and Flux methods.

Hey @Honza,

Thanks for sharing on this False Positive. I see here how the workaround can be seen as cumbersome.

You mention that Mono and Flux can never carry null. Can you explain how come that is? Where library/framework are these constructs coming from?

Best,

Dorian

PS: I have moved your post to the False-positive category as this is not a new rule proposal

It is the Spring WebFlux framework, based on the Project Reactor.

The two key classes are:

Syntactically the framework is based on a fluent interface, the code looks like this:

return Mono.justOrEmpty(request)
    .map(req -> mapper.mapRequest(req))
    .filter(mapperReq -> mapperReq.isValid())
    .flatMap(mapperReq -> myService.getData(mapperReq))
    .map(result -> mapper.mapResult(result));

And you always know that anything on the left side of the lambdas can never be null. There are many more methods of Mono or Flux, map(), flatMap(), and filter() are just the most typical examples.

See e.g. the question and its answers here: spring webflux - Why can't a Mono hold a NULL - Stack Overflow

In WebFlux, once any method is called on a value, it is guaranteed that the value is present. Instead of null, they use Mono.empty() which is handled differently.