markg
markg

Reputation: 23

RxJava2 losing result due to branching logic

I have some kind of Result which I get from a server. I'm trying to build an observable sequence which will: 1. check that the result is successful (result.success()) 2. if it is, then get a string resource from the result (result.getResource()) and return an observable with that string 3. if it's not, then execute some failure handling code and return an empty observable

I can easily achieve that with a simple switchMap however then it contains side effects (the failure handling code) which I don't like because I want to keep the different operations separate if possible. Ideally I'd like to do the failure handling in a separate consumer but the problem is that I cannot pass the result of the .success() method without losing the Result object. Is there a way to achieve what I need?

Right now, my code looks something like this:

Observable<String> getResource() {
            return getServerResult()
            .switchMap(new Function<Result, ObservableSource<String>>() {
                @Override
                public ObservableSource<String> apply(Result result) throws Exception {
                    if (result.success()) {
                        return Observable.just(result.getResource());
                    } else {
                        onFailure(result); // not happy about this side effect being here
                        return Observable.empty();
                    }
                }
            });

Upvotes: 1

Views: 125

Answers (1)

Maksim Ostrovidov
Maksim Ostrovidov

Reputation: 11058

You can make your custom Exception with a result stored in it, wrap it into stream error and return it in flatMap if a result in not successful, call side effect method using doOnError and convert it back to Observable in ErrorResumeNext:

class MyCustomException extends Exception {
    Result result;
}

//do you really need switchMap?
.flatMap(result -> {
    if (result.success()) {
        return Observable.just(result.getResource());
    } else {
        return Observable.error(MyCustomException(result));
    }
})
//do* operators is meant to call side effect methods without changing the stream
.doOnError(exception -> { 
    if(exception instanceof MyCustomException) {
        Result result = ((MyCustomException) exception).getResult();
        onFailure(result);
    }
})
.onErrorResumeNext(exception -> {
    if(exception instanceof MyCustomException) {
        return Observable.empty();
    } else {
        return Observable.error(exception); //propagate error downstream
    }
})

Upvotes: 2

Related Questions