diff --git a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ReactorRules.java b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ReactorRules.java index a98ab8d2e9e..382f1b1cde6 100644 --- a/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ReactorRules.java +++ b/error-prone-contrib/src/main/java/tech/picnic/errorprone/refasterrules/ReactorRules.java @@ -20,6 +20,7 @@ import java.util.HashMap; import java.util.Optional; import java.util.concurrent.Callable; +import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; @@ -650,6 +651,42 @@ Flux after(Flux> flux, int prefetch) { } } + /** + * Prefer {@link Mono#doOnError(Class, Consumer)} over {@link Mono#doOnError(Predicate, Consumer)} + * where possible. + */ + static final class MonoDoOnError { + @BeforeTemplate + Mono before( + Mono mono, Class clazz, Consumer onError) { + return mono.doOnError(clazz::isInstance, onError); + } + + @AfterTemplate + Mono after( + Mono mono, Class clazz, Consumer onError) { + return mono.doOnError(clazz, onError); + } + } + + /** + * Prefer {@link Flux#doOnError(Class, Consumer)} over {@link Flux#doOnError(Predicate, Consumer)} + * where possible. + */ + static final class FluxDoOnError { + @BeforeTemplate + Flux before( + Flux flux, Class clazz, Consumer onError) { + return flux.doOnError(clazz::isInstance, onError); + } + + @AfterTemplate + Flux after( + Flux flux, Class clazz, Consumer onError) { + return flux.doOnError(clazz, onError); + } + } + /** Prefer {@link Mono#onErrorComplete()} over more contrived alternatives. */ static final class MonoOnErrorComplete { @BeforeTemplate @@ -676,16 +713,222 @@ Flux after(Flux flux) { } } - /** Drop redundant {@link Class#isInstance} in {@link Mono#onErrorResume(Function)}. */ + /** Prefer {@link Mono#onErrorComplete(Class)}} over more contrived alternatives. */ + static final class MonoOnErrorCompleteClass { + @BeforeTemplate + Mono before(Mono mono, Class clazz) { + return Refaster.anyOf( + mono.onErrorComplete(clazz::isInstance), mono.onErrorResume(clazz, e -> Mono.empty())); + } + + @AfterTemplate + Mono after(Mono mono, Class clazz) { + return mono.onErrorComplete(clazz); + } + } + + /** Prefer {@link Flux#onErrorComplete(Class)}} over more contrived alternatives. */ + static final class FluxOnErrorCompleteClass { + @BeforeTemplate + Flux before(Flux flux, Class clazz) { + return Refaster.anyOf( + flux.onErrorComplete(clazz::isInstance), + flux.onErrorResume(clazz, e -> Refaster.anyOf(Mono.empty(), Flux.empty()))); + } + + @AfterTemplate + Flux after(Flux flux, Class clazz) { + return flux.onErrorComplete(clazz); + } + } + + /** Prefer {@link Mono#onErrorComplete(Predicate)}} over more contrived alternatives. */ + static final class MonoOnErrorCompletePredicate { + @BeforeTemplate + Mono before(Mono mono, Predicate predicate) { + return mono.onErrorResume(predicate, e -> Mono.empty()); + } + + @AfterTemplate + Mono after(Mono mono, Predicate predicate) { + return mono.onErrorComplete(predicate); + } + } + + /** Prefer {@link Flux#onErrorComplete(Predicate)}} over more contrived alternatives. */ + static final class FluxOnErrorCompletePredicate { + @BeforeTemplate + Flux before(Flux flux, Predicate predicate) { + return flux.onErrorResume(predicate, e -> Refaster.anyOf(Mono.empty(), Flux.empty())); + } + + @AfterTemplate + Flux after(Flux flux, Predicate predicate) { + return flux.onErrorComplete(predicate); + } + } + + /** + * Prefer {@link Mono#onErrorContinue(Class, BiConsumer)} over {@link + * Mono#onErrorContinue(Predicate, BiConsumer)} where possible. + */ + static final class MonoOnErrorContinue { + @BeforeTemplate + Mono before( + Mono mono, + Class clazz, + BiConsumer errorConsumer) { + return mono.onErrorContinue(clazz::isInstance, errorConsumer); + } + + @AfterTemplate + Mono after( + Mono mono, + Class clazz, + BiConsumer errorConsumer) { + return mono.onErrorContinue(clazz, errorConsumer); + } + } + + /** + * Prefer {@link Flux#onErrorContinue(Class, BiConsumer)} over {@link + * Flux#onErrorContinue(Predicate, BiConsumer)} where possible. + */ + static final class FluxOnErrorContinue { + @BeforeTemplate + Flux before( + Flux flux, + Class clazz, + BiConsumer errorConsumer) { + return flux.onErrorContinue(clazz::isInstance, errorConsumer); + } + + @AfterTemplate + Flux after( + Flux flux, + Class clazz, + BiConsumer errorConsumer) { + return flux.onErrorContinue(clazz, errorConsumer); + } + } + + /** + * Prefer {@link Mono#onErrorMap(Class, Function)} over {@link Mono#onErrorMap(Predicate, + * Function)} where possible. + */ + static final class MonoOnErrorMap { + @BeforeTemplate + Mono before( + Mono mono, + Class clazz, + Function mapper) { + return mono.onErrorMap(clazz::isInstance, mapper); + } + + @AfterTemplate + Mono after( + Mono mono, + Class clazz, + Function mapper) { + return mono.onErrorMap(clazz, mapper); + } + } + + /** + * Prefer {@link Flux#onErrorMap(Class, Function)} over {@link Flux#onErrorMap(Predicate, + * Function)} where possible. + */ + static final class FluxOnErrorMap { + @BeforeTemplate + Flux before( + Flux flux, + Class clazz, + Function mapper) { + return flux.onErrorMap(clazz::isInstance, mapper); + } + + @AfterTemplate + Flux after( + Flux flux, + Class clazz, + Function mapper) { + return flux.onErrorMap(clazz, mapper); + } + } + + /** + * Prefer {@link Mono#onErrorResume(Class, Function)} over {@link Mono#onErrorResume(Predicate, + * Function)} where possible. + */ static final class MonoOnErrorResume { @BeforeTemplate - Mono before(Mono mono, Class clazz, Mono other) { - return mono.onErrorResume(clazz::isInstance, e -> other); + Mono before( + Mono mono, + Class clazz, + Function> fallback) { + return mono.onErrorResume(clazz::isInstance, fallback); + } + + @AfterTemplate + Mono after( + Mono mono, + Class clazz, + Function> fallback) { + return mono.onErrorResume(clazz, fallback); + } + } + + /** + * Prefer {@link Flux#onErrorResume(Class, Function)} over {@link Flux#onErrorResume(Predicate, + * Function)} where possible. + */ + static final class FluxOnErrorResume { + @BeforeTemplate + Flux before( + Flux flux, + Class clazz, + Function> fallback) { + return flux.onErrorResume(clazz::isInstance, fallback); + } + + @AfterTemplate + Flux after( + Flux flux, + Class clazz, + Function> fallback) { + return flux.onErrorResume(clazz, fallback); + } + } + + /** + * Prefer {@link Mono#onErrorReturn(Class, Object)} over {@link Mono#onErrorReturn(Predicate, + * Object)} where possible. + */ + static final class MonoOnErrorReturn { + @BeforeTemplate + Mono before(Mono mono, Class clazz, T fallbackValue) { + return mono.onErrorReturn(clazz::isInstance, fallbackValue); + } + + @AfterTemplate + Mono after(Mono mono, Class clazz, T fallbackValue) { + return mono.onErrorReturn(clazz, fallbackValue); + } + } + + /** + * Prefer {@link Flux#onErrorReturn(Class, Object)} over {@link Flux#onErrorReturn(Predicate, + * Object)} where possible. + */ + static final class FluxOnErrorReturn { + @BeforeTemplate + Flux before(Flux flux, Class clazz, T fallbackValue) { + return flux.onErrorReturn(clazz::isInstance, fallbackValue); } @AfterTemplate - Mono after(Mono mono, Class clazz, Mono other) { - return mono.onErrorResume(clazz, e -> other); + Flux after(Flux flux, Class clazz, T fallbackValue) { + return flux.onErrorReturn(clazz, fallbackValue); } } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestInput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestInput.java index 0e7519921eb..b56708a238c 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestInput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestInput.java @@ -208,6 +208,14 @@ ImmutableSet> testConcatMapIterableIdentityWithPrefetch() { Flux.just(ImmutableList.of("bar")).concatMap(Flux::fromIterable, 2)); } + Mono testMonoDoOnError() { + return Mono.just(1).doOnError(IllegalArgumentException.class::isInstance, e -> {}); + } + + Flux testFluxDoOnError() { + return Flux.just(1).doOnError(IllegalArgumentException.class::isInstance, e -> {}); + } + Mono testMonoOnErrorComplete() { return Mono.just(1).onErrorResume(e -> Mono.empty()); } @@ -218,11 +226,63 @@ ImmutableSet> testFluxOnErrorComplete() { Flux.just(2).onErrorResume(e -> Flux.empty())); } + ImmutableSet> testMonoOnErrorCompleteClass() { + return ImmutableSet.of( + Mono.just(1).onErrorComplete(IllegalArgumentException.class::isInstance), + Mono.just(2).onErrorResume(IllegalStateException.class, e -> Mono.empty())); + } + + ImmutableSet> testFluxOnErrorCompleteClass() { + return ImmutableSet.of( + Flux.just(1).onErrorComplete(IllegalArgumentException.class::isInstance), + Flux.just(2).onErrorResume(IllegalStateException.class, e -> Mono.empty()), + Flux.just(3).onErrorResume(AssertionError.class, e -> Flux.empty())); + } + + Mono testMonoOnErrorCompletePredicate() { + return Mono.just(1).onErrorResume(e -> e.getCause() == null, e -> Mono.empty()); + } + + ImmutableSet> testFluxOnErrorCompletePredicate() { + return ImmutableSet.of( + Flux.just(1).onErrorResume(e -> e.getCause() == null, e -> Mono.empty()), + Flux.just(2).onErrorResume(e -> e.getCause() != null, e -> Flux.empty())); + } + + Mono testMonoOnErrorContinue() { + return Mono.just(1).onErrorContinue(IllegalArgumentException.class::isInstance, (e, v) -> {}); + } + + Flux testFluxOnErrorContinue() { + return Flux.just(1).onErrorContinue(IllegalArgumentException.class::isInstance, (e, v) -> {}); + } + + Mono testMonoOnErrorMap() { + return Mono.just(1).onErrorMap(IllegalArgumentException.class::isInstance, e -> e); + } + + Flux testFluxOnErrorMap() { + return Flux.just(1).onErrorMap(IllegalArgumentException.class::isInstance, e -> e); + } + Mono testMonoOnErrorResume() { return Mono.just(1) .onErrorResume(IllegalArgumentException.class::isInstance, e -> Mono.just(2)); } + Flux testFluxOnErrorResume() { + return Flux.just(1) + .onErrorResume(IllegalArgumentException.class::isInstance, e -> Flux.just(2)); + } + + Mono testMonoOnErrorReturn() { + return Mono.just(1).onErrorReturn(IllegalArgumentException.class::isInstance, 2); + } + + Flux testFluxOnErrorReturn() { + return Flux.just(1).onErrorReturn(IllegalArgumentException.class::isInstance, 2); + } + ImmutableSet testContextEmpty() { return ImmutableSet.of(Context.of(new HashMap<>()), Context.of(ImmutableMap.of())); } diff --git a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestOutput.java b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestOutput.java index 795db5fcb45..03a6788e54a 100644 --- a/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestOutput.java +++ b/error-prone-contrib/src/test/resources/tech/picnic/errorprone/refasterrules/ReactorRulesTestOutput.java @@ -210,6 +210,14 @@ ImmutableSet> testConcatMapIterableIdentityWithPrefetch() { Flux.just(ImmutableList.of("bar")).concatMapIterable(identity(), 2)); } + Mono testMonoDoOnError() { + return Mono.just(1).doOnError(IllegalArgumentException.class, e -> {}); + } + + Flux testFluxDoOnError() { + return Flux.just(1).doOnError(IllegalArgumentException.class, e -> {}); + } + Mono testMonoOnErrorComplete() { return Mono.just(1).onErrorComplete(); } @@ -218,10 +226,61 @@ ImmutableSet> testFluxOnErrorComplete() { return ImmutableSet.of(Flux.just(1).onErrorComplete(), Flux.just(2).onErrorComplete()); } + ImmutableSet> testMonoOnErrorCompleteClass() { + return ImmutableSet.of( + Mono.just(1).onErrorComplete(IllegalArgumentException.class), + Mono.just(2).onErrorComplete(IllegalStateException.class)); + } + + ImmutableSet> testFluxOnErrorCompleteClass() { + return ImmutableSet.of( + Flux.just(1).onErrorComplete(IllegalArgumentException.class), + Flux.just(2).onErrorComplete(IllegalStateException.class), + Flux.just(3).onErrorComplete(AssertionError.class)); + } + + Mono testMonoOnErrorCompletePredicate() { + return Mono.just(1).onErrorComplete(e -> e.getCause() == null); + } + + ImmutableSet> testFluxOnErrorCompletePredicate() { + return ImmutableSet.of( + Flux.just(1).onErrorComplete(e -> e.getCause() == null), + Flux.just(2).onErrorComplete(e -> e.getCause() != null)); + } + + Mono testMonoOnErrorContinue() { + return Mono.just(1).onErrorContinue(IllegalArgumentException.class, (e, v) -> {}); + } + + Flux testFluxOnErrorContinue() { + return Flux.just(1).onErrorContinue(IllegalArgumentException.class, (e, v) -> {}); + } + + Mono testMonoOnErrorMap() { + return Mono.just(1).onErrorMap(IllegalArgumentException.class, e -> e); + } + + Flux testFluxOnErrorMap() { + return Flux.just(1).onErrorMap(IllegalArgumentException.class, e -> e); + } + Mono testMonoOnErrorResume() { return Mono.just(1).onErrorResume(IllegalArgumentException.class, e -> Mono.just(2)); } + Flux testFluxOnErrorResume() { + return Flux.just(1).onErrorResume(IllegalArgumentException.class, e -> Flux.just(2)); + } + + Mono testMonoOnErrorReturn() { + return Mono.just(1).onErrorReturn(IllegalArgumentException.class, 2); + } + + Flux testFluxOnErrorReturn() { + return Flux.just(1).onErrorReturn(IllegalArgumentException.class, 2); + } + ImmutableSet testContextEmpty() { return ImmutableSet.of(Context.empty(), Context.empty()); }