Skip to content

Commit 99a620a

Browse files
ZacSweersakarnokd
authored andcommitted
Implement LambdaConsumerIntrospection (#5590)
* Implement HasDefaultErrorConsumer Followup from #5569, and allows you to introspect if the resulting observer has missing error consumption and subsequently supplies a default (throwing) one. * Add `@since` * Add tests * Add support in relevant completable observers * Add support in ConsumerSingleObserver * Add support in MaybeCallbackObserverTest * Add support in LambdaSubscriber * Switch to CompositeObserver and onErrorImplemented() * Update wording to use Introspection * Update tests and flip implementation logic to match naming
1 parent 797301b commit 99a620a

13 files changed

+208
-20
lines changed

src/main/java/io/reactivex/internal/observers/CallbackCompletableObserver.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
import io.reactivex.exceptions.*;
2121
import io.reactivex.functions.*;
2222
import io.reactivex.internal.disposables.DisposableHelper;
23+
import io.reactivex.observers.LambdaConsumerIntrospection;
2324
import io.reactivex.plugins.RxJavaPlugins;
2425

2526
public final class CallbackCompletableObserver
26-
extends AtomicReference<Disposable> implements CompletableObserver, Disposable, Consumer<Throwable> {
27+
extends AtomicReference<Disposable>
28+
implements CompletableObserver, Disposable, Consumer<Throwable>, LambdaConsumerIntrospection {
2729

2830

2931
private static final long serialVersionUID = -4361286194466301354L;
@@ -82,4 +84,9 @@ public void dispose() {
8284
public boolean isDisposed() {
8385
return get() == DisposableHelper.DISPOSED;
8486
}
87+
88+
@Override
89+
public boolean hasCustomOnError() {
90+
return onError != this;
91+
}
8592
}

src/main/java/io/reactivex/internal/observers/ConsumerSingleObserver.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
import io.reactivex.exceptions.*;
2121
import io.reactivex.functions.Consumer;
2222
import io.reactivex.internal.disposables.*;
23+
import io.reactivex.internal.functions.Functions;
24+
import io.reactivex.observers.LambdaConsumerIntrospection;
2325
import io.reactivex.plugins.RxJavaPlugins;
2426

2527
public final class ConsumerSingleObserver<T>
2628
extends AtomicReference<Disposable>
27-
implements SingleObserver<T>, Disposable {
29+
implements SingleObserver<T>, Disposable, LambdaConsumerIntrospection {
2830

2931

3032
private static final long serialVersionUID = -7012088219455310787L;
@@ -74,4 +76,9 @@ public void dispose() {
7476
public boolean isDisposed() {
7577
return get() == DisposableHelper.DISPOSED;
7678
}
79+
80+
@Override
81+
public boolean hasCustomOnError() {
82+
return onError != Functions.ON_ERROR_MISSING;
83+
}
7784
}

src/main/java/io/reactivex/internal/observers/EmptyCompletableObserver.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@
1919
import io.reactivex.disposables.Disposable;
2020
import io.reactivex.exceptions.OnErrorNotImplementedException;
2121
import io.reactivex.internal.disposables.DisposableHelper;
22+
import io.reactivex.observers.LambdaConsumerIntrospection;
2223
import io.reactivex.plugins.RxJavaPlugins;
2324

2425
public final class EmptyCompletableObserver
2526
extends AtomicReference<Disposable>
26-
implements CompletableObserver, Disposable {
27+
implements CompletableObserver, Disposable, LambdaConsumerIntrospection {
2728

2829

2930
private static final long serialVersionUID = -7545121636549663526L;
@@ -55,4 +56,8 @@ public void onSubscribe(Disposable d) {
5556
DisposableHelper.setOnce(this, d);
5657
}
5758

59+
@Override
60+
public boolean hasCustomOnError() {
61+
return false;
62+
}
5863
}

src/main/java/io/reactivex/internal/observers/LambdaObserver.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
import io.reactivex.exceptions.*;
2121
import io.reactivex.functions.*;
2222
import io.reactivex.internal.disposables.DisposableHelper;
23+
import io.reactivex.internal.functions.Functions;
24+
import io.reactivex.observers.LambdaConsumerIntrospection;
2325
import io.reactivex.plugins.RxJavaPlugins;
2426

25-
public final class LambdaObserver<T> extends AtomicReference<Disposable> implements Observer<T>, Disposable {
27+
public final class LambdaObserver<T> extends AtomicReference<Disposable>
28+
implements Observer<T>, Disposable, LambdaConsumerIntrospection {
2629

2730
private static final long serialVersionUID = -7251123623727029452L;
2831
final Consumer<? super T> onNext;
@@ -101,4 +104,9 @@ public void dispose() {
101104
public boolean isDisposed() {
102105
return get() == DisposableHelper.DISPOSED;
103106
}
107+
108+
@Override
109+
public boolean hasCustomOnError() {
110+
return onError != Functions.ON_ERROR_MISSING;
111+
}
104112
}

src/main/java/io/reactivex/internal/operators/maybe/MaybeCallbackObserver.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import io.reactivex.exceptions.*;
2121
import io.reactivex.functions.*;
2222
import io.reactivex.internal.disposables.DisposableHelper;
23+
import io.reactivex.internal.functions.Functions;
24+
import io.reactivex.observers.LambdaConsumerIntrospection;
2325
import io.reactivex.plugins.RxJavaPlugins;
2426

2527
/**
@@ -29,7 +31,7 @@
2931
*/
3032
public final class MaybeCallbackObserver<T>
3133
extends AtomicReference<Disposable>
32-
implements MaybeObserver<T>, Disposable {
34+
implements MaybeObserver<T>, Disposable, LambdaConsumerIntrospection {
3335

3436

3537
private static final long serialVersionUID = -6076952298809384986L;
@@ -96,5 +98,8 @@ public void onComplete() {
9698
}
9799
}
98100

99-
101+
@Override
102+
public boolean hasCustomOnError() {
103+
return onError != Functions.ON_ERROR_MISSING;
104+
}
100105
}

src/main/java/io/reactivex/internal/subscribers/LambdaSubscriber.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
import java.util.concurrent.atomic.AtomicReference;
1717

18+
import io.reactivex.internal.functions.Functions;
19+
import io.reactivex.observers.LambdaConsumerIntrospection;
1820
import org.reactivestreams.Subscription;
1921

2022
import io.reactivex.FlowableSubscriber;
@@ -24,7 +26,8 @@
2426
import io.reactivex.internal.subscriptions.SubscriptionHelper;
2527
import io.reactivex.plugins.RxJavaPlugins;
2628

27-
public final class LambdaSubscriber<T> extends AtomicReference<Subscription> implements FlowableSubscriber<T>, Subscription, Disposable {
29+
public final class LambdaSubscriber<T> extends AtomicReference<Subscription>
30+
implements FlowableSubscriber<T>, Subscription, Disposable, LambdaConsumerIntrospection {
2831

2932
private static final long serialVersionUID = -7251123623727029452L;
3033
final Consumer<? super T> onNext;
@@ -115,4 +118,9 @@ public void request(long n) {
115118
public void cancel() {
116119
SubscriptionHelper.cancel(this);
117120
}
121+
122+
@Override
123+
public boolean hasCustomOnError() {
124+
return onError != Functions.ON_ERROR_MISSING;
125+
}
118126
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.reactivex.observers;
2+
3+
import io.reactivex.annotations.Experimental;
4+
5+
/**
6+
* An interface that indicates that the implementing type is composed of individual components and exposes information
7+
* about their behavior.
8+
*
9+
* <p><em>NOTE:</em> This is considered a read-only public API and is not intended to be implemented externally.
10+
*
11+
* @since 2.1.4 - experimental
12+
*/
13+
@Experimental
14+
public interface LambdaConsumerIntrospection {
15+
16+
/**
17+
* @return {@code true} if a custom onError consumer implementation was supplied. Returns {@code false} if the
18+
* implementation is missing an error consumer and thus using a throwing default implementation.
19+
*/
20+
@Experimental
21+
boolean hasCustomOnError();
22+
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package io.reactivex.internal.observers;
2+
3+
import io.reactivex.internal.functions.Functions;
4+
import org.junit.Test;
5+
6+
import static org.junit.Assert.*;
7+
8+
public final class CallbackCompletableObserverTest {
9+
10+
@Test
11+
public void emptyActionShouldReportNoCustomOnError() {
12+
CallbackCompletableObserver o = new CallbackCompletableObserver(Functions.EMPTY_ACTION);
13+
14+
assertFalse(o.hasCustomOnError());
15+
}
16+
17+
@Test
18+
public void customOnErrorShouldReportCustomOnError() {
19+
CallbackCompletableObserver o = new CallbackCompletableObserver(Functions.<Throwable>emptyConsumer(),
20+
Functions.EMPTY_ACTION);
21+
22+
assertTrue(o.hasCustomOnError());
23+
}
24+
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package io.reactivex.internal.observers;
2+
3+
import io.reactivex.internal.functions.Functions;
4+
import org.junit.Test;
5+
6+
import static org.junit.Assert.*;
7+
8+
public final class ConsumerSingleObserverTest {
9+
10+
@Test
11+
public void onErrorMissingShouldReportNoCustomOnError() {
12+
ConsumerSingleObserver<Integer> o = new ConsumerSingleObserver<Integer>(Functions.<Integer>emptyConsumer(),
13+
Functions.ON_ERROR_MISSING);
14+
15+
assertFalse(o.hasCustomOnError());
16+
}
17+
18+
@Test
19+
public void customOnErrorShouldReportCustomOnError() {
20+
ConsumerSingleObserver<Integer> o = new ConsumerSingleObserver<Integer>(Functions.<Integer>emptyConsumer(),
21+
Functions.<Throwable>emptyConsumer());
22+
23+
assertTrue(o.hasCustomOnError());
24+
}
25+
26+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package io.reactivex.internal.observers;
2+
3+
import org.junit.Test;
4+
5+
import static org.junit.Assert.assertFalse;
6+
7+
public final class EmptyCompletableObserverTest {
8+
9+
@Test
10+
public void defaultShouldReportNoCustomOnError() {
11+
EmptyCompletableObserver o = new EmptyCompletableObserver();
12+
13+
assertFalse(o.hasCustomOnError());
14+
}
15+
}

src/test/java/io/reactivex/internal/observers/LambdaObserverTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.*;
1919

20+
import io.reactivex.internal.functions.Functions;
2021
import org.junit.Test;
2122

2223
import io.reactivex.Observable;
@@ -342,4 +343,24 @@ public void accept(Disposable s) throws Exception {
342343

343344
assertTrue(errors.toString(), errors.get(0) instanceof TestException);
344345
}
346+
347+
@Test
348+
public void onErrorMissingShouldReportNoCustomOnError() {
349+
LambdaObserver<Integer> o = new LambdaObserver<Integer>(Functions.<Integer>emptyConsumer(),
350+
Functions.ON_ERROR_MISSING,
351+
Functions.EMPTY_ACTION,
352+
Functions.<Disposable>emptyConsumer());
353+
354+
assertFalse(o.hasCustomOnError());
355+
}
356+
357+
@Test
358+
public void customOnErrorShouldReportCustomOnError() {
359+
LambdaObserver<Integer> o = new LambdaObserver<Integer>(Functions.<Integer>emptyConsumer(),
360+
Functions.<Throwable>emptyConsumer(),
361+
Functions.EMPTY_ACTION,
362+
Functions.<Disposable>emptyConsumer());
363+
364+
assertTrue(o.hasCustomOnError());
365+
}
345366
}

src/test/java/io/reactivex/internal/operators/maybe/MaybeCallbackObserverTest.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,17 @@
1313

1414
package io.reactivex.internal.operators.maybe;
1515

16-
import static org.junit.Assert.*;
17-
18-
import java.util.List;
19-
20-
import org.junit.Test;
21-
2216
import io.reactivex.TestHelper;
2317
import io.reactivex.disposables.*;
2418
import io.reactivex.exceptions.*;
2519
import io.reactivex.functions.*;
2620
import io.reactivex.internal.functions.Functions;
2721
import io.reactivex.plugins.RxJavaPlugins;
22+
import org.junit.Test;
23+
24+
import java.util.List;
25+
26+
import static org.junit.Assert.*;
2827

2928
public class MaybeCallbackObserverTest {
3029

@@ -121,4 +120,22 @@ public void run() throws Exception {
121120
RxJavaPlugins.reset();
122121
}
123122
}
123+
124+
@Test
125+
public void onErrorMissingShouldReportNoCustomOnError() {
126+
MaybeCallbackObserver<Integer> o = new MaybeCallbackObserver<Integer>(Functions.<Integer>emptyConsumer(),
127+
Functions.ON_ERROR_MISSING,
128+
Functions.EMPTY_ACTION);
129+
130+
assertFalse(o.hasCustomOnError());
131+
}
132+
133+
@Test
134+
public void customOnErrorShouldReportCustomOnError() {
135+
MaybeCallbackObserver<Integer> o = new MaybeCallbackObserver<Integer>(Functions.<Integer>emptyConsumer(),
136+
Functions.<Throwable>emptyConsumer(),
137+
Functions.EMPTY_ACTION);
138+
139+
assertTrue(o.hasCustomOnError());
140+
}
124141
}

src/test/java/io/reactivex/internal/subscribers/LambdaSubscriberTest.java

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,20 @@
1313

1414
package io.reactivex.internal.subscribers;
1515

16-
import static org.junit.Assert.*;
17-
18-
import java.util.*;
19-
20-
import org.junit.Test;
21-
import org.reactivestreams.*;
22-
2316
import io.reactivex.*;
2417
import io.reactivex.exceptions.*;
2518
import io.reactivex.functions.*;
19+
import io.reactivex.internal.functions.Functions;
20+
import io.reactivex.internal.operators.flowable.FlowableInternalHelper;
2621
import io.reactivex.internal.subscriptions.BooleanSubscription;
2722
import io.reactivex.plugins.RxJavaPlugins;
2823
import io.reactivex.processors.PublishProcessor;
24+
import org.junit.Test;
25+
import org.reactivestreams.*;
26+
27+
import java.util.*;
28+
29+
import static org.junit.Assert.*;
2930

3031
public class LambdaSubscriberTest {
3132

@@ -347,4 +348,24 @@ public void accept(Subscription s) throws Exception {
347348

348349
assertTrue(errors.toString(), errors.get(0) instanceof TestException);
349350
}
351+
352+
@Test
353+
public void onErrorMissingShouldReportNoCustomOnError() {
354+
LambdaSubscriber<Integer> o = new LambdaSubscriber<Integer>(Functions.<Integer>emptyConsumer(),
355+
Functions.ON_ERROR_MISSING,
356+
Functions.EMPTY_ACTION,
357+
FlowableInternalHelper.RequestMax.INSTANCE);
358+
359+
assertFalse(o.hasCustomOnError());
360+
}
361+
362+
@Test
363+
public void customOnErrorShouldReportCustomOnError() {
364+
LambdaSubscriber<Integer> o = new LambdaSubscriber<Integer>(Functions.<Integer>emptyConsumer(),
365+
Functions.<Throwable>emptyConsumer(),
366+
Functions.EMPTY_ACTION,
367+
FlowableInternalHelper.RequestMax.INSTANCE);
368+
369+
assertTrue(o.hasCustomOnError());
370+
}
350371
}

0 commit comments

Comments
 (0)