Hello,
I’d like to share a context where rule kotlin:S6508 fires on code that
follows the documented convention of an underlying library, in case it is
useful to the team.
Context
In Kotlin code that uses Project Reactor, the conventional return type for a
publisher that completes without emitting a value is Mono<Void>. This is
recommended by the Reactor Mono API documentation, which says (quoted from
the JavaDoc summary):
Mono<Void>should be used forPublisherthat just completes without any
value. It is intended to be used in implementations and return types, input
parameters should keep using rawPublisheras much as possible.
Source: Mono (reactor-core 3.8.5)
Reactor operators such as .then() and Mono.when(...) produce Mono<Void>
values directly, and many Java-based libraries that integrate with Reactor
(Spring WebFlux among others) expose Mono<Void> in their public APIs.
My concern with Mono<Unit> as a replacement
As far as I can tell, Mono<Void> and Mono<Unit> differ semantically in
Reactor’s protocol:
Mono<Void>emits onlyonCompleteoronError, neveronNext.Mono<Unit>emits a singleUnitvalue viaonNextbefore completing.
If that is correct, substituting Mono<Unit> changes the reactive signal that
downstream operators observe, and requires inserting .thenReturn(Unit) at
every call site that currently uses .then(). I am not a Reactor expert, so
the team may have a clearer view on whether this distinction matters in
practice.
Minimal reproducer
import reactor.core.publisher.Mono
class Example {
// Conventional Reactor return type for a publisher that completes
// without emitting a value. kotlin:S6508 is reported on `Mono<Void>`.
fun process(input: Mono<String>): Mono<Void> =
input
.doOnNext { println(it) }
.then()
}
Versions
- SonarQube: Community Edition 26.1.0.118079
- SonarQube for IDE: 12.2.2.84629 (connected to the SonarQube server above)
sonar-kotlinanalyzer: (not sure where to find this; happy to provide it if you can point me to the right place in the analysis logs)- Kotlin: 1.9.25
reactor-core: 3.6.1
One possible direction
I noticed that pull request #677 (SONARKT-703) narrowed S6508 so it does not
fire on functions implementing parent class / interface signatures. I wonder
whether a similar approach could work here, for example not reporting when
Void appears as a type argument to a Reactor publisher type. That said, the
team knows the rule far better than I do, so I am just sharing the context and
happy to provide more examples if it would help.
Thanks for the work on the analyzer.