Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce Mono#using{,When} Refaster rules #1393

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

mohamedsamehsalah
Copy link
Contributor

@mohamedsamehsalah mohamedsamehsalah commented Nov 3, 2024

Suggested commit message

Introduce `Mono#using{When}` reactor refaster rules

@mohamedsamehsalah mohamedsamehsalah added this to the 0.20.0 milestone Nov 3, 2024
Copy link

github-actions bot commented Nov 3, 2024

Looks good. No mutations were possible for these changes.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

D extends AutoCloseable, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
@BeforeTemplate
Flux<T> before(Callable<D> resourceSupplier, Function<D, M> sourceSupplier) {
return Mono.using(resourceSupplier, sourceSupplier).flux();
Copy link
Contributor

@Venorcis Venorcis Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure I agree with this one; using Mono#flux at least makes explicit that it can emit at most 1 element (and sometimes a Flux is needed to adhere to method signatures)

the other way around is fine ofc. (Flux#single should generally only be used in specific edge cases, e.g. requesting 1 element from a batched endpoint)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure I agree with this one; using Mono#flux at least makes explicit that it can emit at most 1 element (and sometimes a Flux is needed to adhere to method signatures)

If you check the method signature (Also what I was trying to explain here), is that the Function of the sourceSupplier explicitly returns a Mono, so by definition, we know the whole chain returns one element. So the Mono > Flux conversion seems redundant to me.

WDYT?

Copy link
Contributor

@Venorcis Venorcis Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flux.using with a Mono sourceSupplier looks worse to me as IMO that just obfuscates what's going on, and thus I'd favour the explicit conversion with flux() (which is only needed in specific cases, for example adhering to a method return signature with multiple cases)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that makes sense to me 👌

Just to make sure I understand your stance, is this a "choosing a lesser evil" type of design choice? Or do you think that what we're attempting to re-write is actually a valid case?

Copy link
Contributor

@Venorcis Venorcis Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or do you think that what we're attempting to re-write is actually a valid case

Yeah, I think Mono#flux should generally not be rewritten (bar some very specific exceptions where it's ultra-clear the Flux-variant only supplies 1 element, i.e. with just and error)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fair argument, I honestly have no strong opinion here.

Let's see what others think, then I will happily close the PR 😄 Thanks @Venorcis

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the other way around is very valid though 😄 i.e. don't use Flux#single when you can directly use a Mono instead

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

..using Mono#flux at least makes explicit that it can emit at most 1 element ...

Though it is hard to know if the pattern was applied because it was intentionally specifying a flux that emits one element; or simply an unawareness of the equivalent APIs in Flux; Let's assume the former 👍

Applied ✅

Copy link
Contributor

@Venorcis Venorcis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one could think of more very weird (but very straightforward) ones like:

  • Flux.error(...).single() / Mono.error(...).flux
  • Flux.empty().single() / Mono.empty().flux
  • Flux.just(...).single() / Mono.just(...).flux (not the Flux array signature ofc.)

and even most zip \ zipWith variants I guess

Copy link
Contributor Author

@mohamedsamehsalah mohamedsamehsalah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for review @Venorcis 🙏

one could think of more very weird (but very straightforward) ones like:

  • Flux.error(...).single() / Mono.error(...).flux
  • Flux.empty().single() / Mono.empty().flux
  • Flux.just(...).single() / Mono.just(...).flux (not the Flux array signature ofc.)

and even most zip \ zipWith variants I guess

I agree. I wanted to limit the scope of this refaster rule to the #using API. Which started when I unknowingly had the same pattern in one of my PRs.

D extends AutoCloseable, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
@BeforeTemplate
Flux<T> before(Callable<D> resourceSupplier, Function<D, M> sourceSupplier) {
return Mono.using(resourceSupplier, sourceSupplier).flux();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure I agree with this one; using Mono#flux at least makes explicit that it can emit at most 1 element (and sometimes a Flux is needed to adhere to method signatures)

If you check the method signature (Also what I was trying to explain here), is that the Function of the sourceSupplier explicitly returns a Mono, so by definition, we know the whole chain returns one element. So the Mono > Flux conversion seems redundant to me.

WDYT?

@mohamedsamehsalah mohamedsamehsalah force-pushed the mohamedsamehsalah/mono-using branch from 472962e to 49c3848 Compare November 19, 2024 12:40
@mohamedsamehsalah mohamedsamehsalah changed the title Introduce {Mono|Flux}#using{When} reactor refaster rules Introduce Mono#using{When} reactor refaster rules Nov 19, 2024
Copy link

Looks good. No mutations were possible for these changes.
Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

D extends AutoCloseable, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
@BeforeTemplate
Mono<T> before(Callable<D> resourceSupplier, Function<D, P> sourceSupplier) {
return Flux.using(resourceSupplier, sourceSupplier).single();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Here & below)
This refaster rule will cause a compiler error if the publisher in the supplier is not of type Mono. 😬

(Need to think how I can improve the matching here)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Introduced a before template matcher here.

D extends AutoCloseable, T, P extends Publisher<? extends T>, M extends Mono<? extends T>> {
@BeforeTemplate
Flux<T> before(Callable<D> resourceSupplier, Function<D, M> sourceSupplier) {
return Mono.using(resourceSupplier, sourceSupplier).flux();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

..using Mono#flux at least makes explicit that it can emit at most 1 element ...

Though it is hard to know if the pattern was applied because it was intentionally specifying a flux that emits one element; or simply an unawareness of the equivalent APIs in Flux; Let's assume the former 👍

Applied ✅

Copy link

Looks good. All 7 mutations in this change were killed.

class surviving killed
🎉tech.picnic.errorprone.refaster.matchers.IsFunctionReturningMono 0 7

Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

Copy link
Contributor

@Venorcis Venorcis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very niche, but LGTM 😄

Copy link

Looks good. All 7 mutations in this change were killed.

class surviving killed
🎉tech.picnic.errorprone.refaster.matchers.IsFunctionReturningMono 0 7

Mutation testing report by Pitest. Review any surviving mutants by inspecting the line comments under Files changed.

@rickie rickie changed the title Introduce Mono#using{When} reactor refaster rules Introduce Mono#using{,When} Refaster rules Dec 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants