In this blog, he gives this (copy/pasted the following code) example for the callback hell. However, there is no mention of how the issue can be eliminated by using Reactive
According to your code. Suppose that the remote call are done using Observable
.
Observable<Integer> callRemoveServiceA() { /* async call */ }
/* .... */
Observable<Integer> callRemoveServiceE(Integer f2) { /* async call */ }
What you want :
serviceA
then call serviceB
with the result of serviceA
serviceC
then call serviceD
and serviceE
with the result of serviceC
serviceE
and serviceD
, build a new valueserviceB
With RxJava, you'll achieve this with this code :
Observable<Integer> f3 = callRemoveServiceA() // call serviceA
// call serviceB with the result of serviceA
.flatMap((f1) -> callRemoveServiceB(f1));
Observable<Integer> f4Andf5 = callRemoveServiceC() // call serviceC
// call serviceD and serviceE then build a new value
.flatMap((f2) -> callRemoveServiceD(f2).zipWith(callRemoveServiceE(f2), (f4, f5) -> f4 * f5));
// compute the string to display from f3, and the f4, f5 pair
f3.zipWith(f4Andf5, (childF3, childF4Andf5) -> childF3 + " => " + childF4Andf5)
// display the value
.subscribe(System.out::println);
the important part here is the use of flapMap
and zip
(or zipWith
)
flapMap
will transform a value into another Observable
. This Observable
here will be your new asynchronos call. ( http://reactivex.io/documentation/operators/flatmap.html )zip
will compose a new value from two different Observable
. So you can build a new value with the result of two (or more) Obsevable
( http://reactivex.io/documentation/operators/zip.html )You can get more info on flapMap here : When do you use map vs flatMap in RxJava?
I'm the original author of the referenced blog post about callbacks and Java Futures. Here is an example of using flatMap, zip and merge to do service composition asynchronously.
It fetches a User object, then concurrently fetches Social and PersonalizedCatalog data, then for each Video from the PersonalizedCatalog concurrently fetches a Bookmark, Rating and Metadata, zips those together, and merges all of the responses into a progressive stream output as Server-Sent Events.
return getUser(userId).flatMap(user -> {
Observable<Map<String, Object>> catalog = getPersonalizedCatalog(user)
.flatMap(catalogList -> catalogList.videos().<Map<String, Object>> flatMap(
video -> {
Observable<Bookmark> bookmark = getBookmark(video);
Observable<Rating> rating = getRatings(video);
Observable<VideoMetadata> metadata = getVideoMetadata(video);
return Observable.zip(bookmark, rating, metadata, (b, r, m) -> combineVideoData(video, b, r, m));
}));
Observable<Map<String, Object>> social = getSocial(user).map(s -> {
return s.getDataAsMap();
});
return Observable.merge(catalog, social);
}).flatMap(data -> {
String json = SimpleJson.mapToJson(data);
return response.writeStringAndFlush("data: " + json + "\n");
});
This example can be seen in context of a functioning application at https://github.com/Netflix/ReactiveLab/blob/952362b89a4d4115ae0eecf0e73f273ecb27ba98/reactive-lab-gateway/src/main/java/io/reactivex/lab/gateway/routes/RouteForDeviceHome.java#L33
Since I can't possibly provide all of the information here you can also find an explanation in presentation form (with link to video) at https://speakerdeck.com/benjchristensen/reactive-streams-with-rx-at-javaone-2014?slide=32.