RxJava2: convert Completable to Single - are the approaches equivalent? - rx-java2

Given a Completable called "completable". I want to convert completable to a Single providing a default value.
I originally used this approach:
completable.andThen(Single.just(defaultValue))
A colleague created a bugfix pull request replacing the line with:
completable.toSingleDefault(defaultValue)
While I have to admit this is easier to read anyway, I'm wondering: is this a bugfix or a refactoring?

the difference is in the error case.
completable.Single.just(dv): Returns a {#code Single} that emits a specified item.
Always emits Single.just(dv)
completable.toSingleDefault(dv): Converts this Completable into a Single which when this Completable completes normally, emits the given value through onSuccess.
Emits Single.error() or Single.just(dv) depending on the state of completable

Related

Issue with my usage of project reactor or() operator [duplicate]

I would like to chain Monos and emit the first non-empty of them. I thought the or() operator was designed for this purpose.
Here is my chain of Monos: first one is empty and second one should emit "hello".
#Test
void orTest() {
Mono<String> chain = Mono.<String>empty().or(Mono.just("hello"));
StepVerifier.create(
chain
)
.expectNext("hello")
.verifyComplete();
}
However, I get the following failure:
java.lang.AssertionError: expectation "expectNext(hello)" failed (expected: onNext(hello); actual: onComplete())
Can someone please help? What I am getting wrong here?
You misunderstand or() - it takes the first result emitted from either publisher. That's very different from the first item emitted - if one of the Mono objects emits an onComplete() result without returning anything, then, as is happening in your case, you'll get that result with nothing emitted.
You can see this behaviour if you do something like Mono.<String>empty().delaySubscription(Duration.ofMillis(100)).or(Mono.just("hello")); instead, which will almost certainly pass (as the onComplete() result of the emtpy Mono is delayed sufficiently for the other Mono to emit an item first.)
However, the method you're after is switchIfEmpty(), which (as the name suggests) will wait for the first Mono to complete, then fallback to the second if the first returns an empty result:
#Test
public void orTest() {
Mono<String> chain = Mono.<String>empty().switchIfEmpty(Mono.just("hello"));
StepVerifier.create(chain)
.expectNext("hello")
.verifyComplete();
}

Confused about Observable vs. Single in functions like readCharacteristic()

In the RxJava2 version of RxAndroidBle, the functions readCharacteristic() and writeCharacteristic() return Single<byte[]>.
The example code to read a characteristic is:
device.establishConnection(false).flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(characteristicUUID))
But the documentation for flatMap() says the mapping function is supposed to return an ObservableSource. Here, it returns a Single. How can this work?
Update: I looked at possibilities using operators like .single() and .singleOrError() but they all seem to require that the upstream emits one item and then completes. But establishConnection() doesn't ever complete. (This is one reason I suggested that perhaps establishConnection() should be reimagined as a Maybe, and some other way be provided to disconnect rather than just unsubscribing.)
You're totally correct, this example cannot be compiled. it's probably leftover from RxJava1 version, where Single wasn't exists.
Simple fix with the same result is to use RxJava2 flatMapSingle for instance:
device.establishConnection(false)
.flatMapSingle(rxBleConnection -> rxBleConnection.readCharacteristic(characteristicUUID))
flatMapSingle accepts a Single as the return value, and will map the success value of the input Single to an emission from the upstream Observable.
The point is, that RxJava has more specific Observable types, that exposes the possible series of emission expected from this Observable. Some methods now return Single as this is the logical operation of their stream (readCharacteristic()), some Observable as they will emit more than single emission (establishConnection() - connection status that can be changed over time).
But RxJava2 also provided many operators to convert between the different types and it really depends on your needs and scenario.
Thanks Rob!
In fact, the README was deprecated and required some pimping here and there. Please have a look if it's ok now.
I think I found the answer I was looking for. The crucial point:
Single.fromObservable(observableSource) doesn't do anything until it receives the second item from observableSource! Assuming that the first item it receives is a valid emission, then if the second item is:
onComplete(), it passes the first item to onSuccess();
onNext(), it signals IndexOutOfBoundsException since a Single can't emit more than one item;
onError(), it presumably forwards the error downstream.
Now, device.establishConnection() is a 1-item, non-completing Observable. The RxBleConnecton it emits is flatMapped to a Single with readCharacteristic(). But (another gotcha), flatMapSingle subscribes to these Singles and combines them into an Observable, which doesn't complete until the source establishConnection() does. But the source doesn't ever complete! Therefore the Single we're trying to create won't emit anything, since it doesn't receive that necessary second item.
The solution is to force the generation of onComplete() after the first (and only) item, which can be done with take(1). This will satisfy the Single we're creating, and cause it to emit the Characteristic value we're interested in. Hope that's clear.
The code:
Single<byte[]> readCharacteristicSingle( RxBleDevice device, UUID characteristicUUID ) {
return Single.fromObservable(
device.establishConnection( false )
.flatMapSingle( connection -> connection.readCharacteristic( characteristicUUID ) )
.take( 1L ) // make flatMapSingle's output Observable complete after the first emission
// (this makes the Single call onSuccess())
);
}

Auto-complete a Single created from another Observable

I have a long-running operation that returns a value in code I don't control. I need that value to be published to things that ask for it. For this purpose I am using a BehaviorSubject:
var subject: Subject<Value>? = null
fun retrieveValue(): Single<Value> {
if (subject == null) {
subject = BehaviorSubject.create<Value>()
someOtherThing.retrieveValueAsync { value ->
subject.onNext(value)
}
}
return subject.singleOrError()
}
This lets me perform the operation only once and send the result as a single to all future interested parties. However, it does not work. The single will not emit a value until I call:
subject.onComplete()
But this is a problem because once the subject is completed future things can no longer subscribe to it.
What is the appropriate way to cache a value from another observable and pass it to a Single? If there was a way to have a subject automatically complete once its source observable emitted a value that would work. Single.cache() also looks promising, but I'm unsure how I would handle the fact that my value comes in asynchronously in that case.
It feels like I'm missing something silly.
There is a SingleSubject for this case.
If you don't want experimental code in your codebase, you can use ReplaySubject.createWithSize(1) and call onComplete without losing the last value, then convert it to Single.

Can an Rx Observable gracefully handle exceptions in an operator and continue?

i.e., by passing the error condition and not halting the entire Observable?
My Observable starts with a user-supplied list of package tracking numbers from common delivery services (FedEx, UPS, DHL, etc), looks up the expected delivery date online, then returns those dates in terms of number of days from today (i.e. "in 3 days" rather than "Jan 22"). The problem is that if any individual lookup results in an exception, the entire stream halts, and the rest of the codes won't be looked up. There's no ability to gracefully handle, say, UnknownTrackingCode Exception, and so the Observable can't guarantee that it will look up all the codes the user submitted.
public void getDaysTillDelivery(List<String> tracking_code_list) {
Observable o = Observable.from(tracking_code_list)
// LookupDeliveryDate performs network calls to UPS, FedEx, USPS web sites or APIs
// it might throw: UnknownTrackingCode Exception, NoResponse Exception, LostPackage Exception
.map(tracking_code -> LookupDeliveryDate(tracking_code))
.map(delivery_date -> CalculateDaysFromToday(delivery_date));
o.subscribe(mySubscriber); // will handle onNext, onError, onComplete
}
Halting the Observable stream as a result of one error is by design:
http://reactivex.io/documentation/operators/catch.html
Handling Exceptions in Reactive Extensions without stopping sequence
https://groups.google.com/forum/#!topic/rxjava/trm2n6S4FSc
The default behavior can be overcome, but only by eliminating many of the benefits of Rx in the first place:
I can wrap LookupDeliveryDate so it returns Dates in place of Exceptions (such as 1899-12-31 for UnknownTrackingCode Exception) but this prevents "loosely coupled code", because CalculateDaysFromToday would need to handle these special cases
I can surround each anonymous function with try/catch and blocks, but this essentially prevents me from using lambdas
I can use if/thens to direct the code path, but this will likely require maintaining some state and eliminating deterministic evaluation
Error handling of each step, obviously, prevents consolidating all error handling in the Subscriber
Writing my own error-handling operator is possible, but thinly documented
Is there a better way to handle this?
What exactly do you want to happen if there is an error? Do you just want to throw that entry away or do you want something downstream to do something with it?
If you want something downstream to take some action, then you are really turning the error into data (sort of like your example of returning a sentinel value of 1899-12-31 to represent the error). This strategy by definition means that everything downstream needs to understand that the data stream may contain errors instead of data and they must be modified to deal with it.
But rather than yielding a magic value, you can turn your Observable stream into a stream of Either values. Either the value is a date, or it is an error. Everything downstream receives this Either object and can ask it if it has a value or an error. If it has a value, they can produce a new Either object with the result of their calculation. If it has an error and they cannot do anything with it, they can yield an error Either themselves.
I don't know Java syntax, but this is what it might look like in c#:
Observable.From(tracking_code_list)
.Select(t =>
{
try { return Either.From(LookupDeliveryDate(t)); }
catch (Exception e)
{
return Either.FromError<Date>(e);
}
})
.Select(dateEither =>
{
return dateEither.HasValue ?
Either.From(CalculateDaysFromToday(dateEither.Value)) :
Either.FromError<int>(dateEither.Error);
})
.Subscribe(value =>
{
if (value.HasValue) mySubscriber.OnValue(value.Value);
else mySubscribe.OnError(value.Error);
});
Your other option is the "handle"/suppress the error when it occurs. This may be sufficient depending on your needs. In this case, just have LookupDeliveryDate return magic dates instead of exceptions and then add a .filter to filter out the magic dates before they get to CalculateDaysFromToay.

Serving multiple result Futures as soon as available to a client

I have a page that is populated by data that I get using different calls to distant servers. Some requests take longer than others, the way I do things now is that I do all the calls at once and wrap the whole thing in a Future, then put the the whole thing in a Action.async for Play to handle.
This, theoretically, does the job but I don't want my users to be waiting a long time and instead start loading the page part by part. Meaning that as soon as data is available for a given request to a distant server, it should be sent to the client as Json or whatever.
I was able to partially achieve this using EventSource by modifying Play's event-source sample by doing something like this:
Ok.chunked((enumerator1 &> EventSource()) >- (enumerator2 &> EventSource())).as("text/event-stream")
and the enumerators as follows:
val enumerator1: Enumerator[String] = Enumerator.generateM{
Future[Option[String]]{Thread.sleep(1500); Some("Hello")}
}
val enumerator2: Enumerator[String] = Enumerator.generateM{
Future[Option[String]]{Thread.sleep(2000); Some("World!")}
}
As you probably have guessed, I was expecting to have "Hello" after 1.5s and then "World!" 0.5s later sent to the client, but I ended up receiving "Hello" every 1.5s and "World!" every 2s.
My questions are:
Is there a way to stop sending an information once it has been correctly delivered to the client using the method above?
Is there a better way to achieve what I want?
You don't want generateM, it's for building enumerators that can return multiple values. generateM takes a function that either returns a Some, to produce the next value for the Enumerator, or None, to signal that the Enumerator is complete. Because your function always returns Some, you create Enumerators that are infinite in length.
You just want to convert a Future into an Enumerator, to create an Enumerator with a single element:
Enumerator.flatten(future.map(Enumerator(_)))
Also, you can interleave your enumerators and then feed the result into EventSource(). Parenthesis are unnecessary as well (methods that start with > have precedence over methods with &).
enumerator1 >- enumerator2 &> EventSource()