I need to create an observable where 2 blocks of retrofit based calls are run sequentially. I know I can just run the second retrofit call inside one Observer call but it will be pretty messy. I have my Observable code in a separate class from the caller and it returns an Observable. I'd like to pass the result of the first call to the second then when the second call is done pass back an Observable to the calling class. (I'm using Java 7 and not 8)
public class GetFollowing {
public Observable< ArrayList<Media> > init() {
return Observable.create(
new Observable.OnSubscribe< ArrayList<Media> >() {
#Override
public void call(Subscriber<? super ArrayList<Media> > subscriber) {
...
I also need to pass back to the calling class a different type than I pass to teh second retrofit call. I been reading about map flatMap and concat but I can't seem to figure out how to structure them for my use here.
UPDATE
I came up with this, not sure if its the most elegant or if it will work at all...but if it does work is there any way to pass the result of first observable to second? Also how would I handle an issue if first observable fails?
Observable< ArrayList<Media> > test;
Observable.concat(
Observable.create(
new Observable.OnSubscribe< ArrayList<User> >() {
#Override
public void call(Subscriber<? super ArrayList<User> > subscriber) {
}
}
),
test = Observable.create(
new Observable.OnSubscribe< ArrayList<Media> >() {
#Override
public void call(Subscriber<? super ArrayList<Media> > subscriber) {
}
}
)
);
return test;
If the the requirement can be rephrased as below:
You have two methods to be executed and both return Observables.
The items emitted on first method's Observable needs to be fed into the second method as and when they occur.
The output of second method is an Observable which is based on some computation on items of first Observable.
The readily available flatMap feature in RxJava is the solution for you. Below is a simple implementation to assist you.
public static void main(String[] args) {
Observable<Integer> o1 = Observable.just(1, 2);
Observable<String> result = o1.flatMap(result1 -> Observable.just("Value is: "+result1));
result.subscribe(finalResult -> System.out.println("Final result: "+finalResult));
}
Output:
Final result: Value is: 1
Final result: Value is: 2
On the other side, if second method does not return an Observable, but performs some operation on the emitted item, you can implement the same using map.
Related
I use Spring WebFlux (Project Reactor) and I'm facing the following problem:
I have to get some data from db to use them to call another service - everything in one stream. How to do that?
public Mono<MyObj> saveObj(Mono<MyObj> obj) {
return obj
.flatMap(
ob->
Mono.zip(
repo1.save(
...),
repo2
.saveAll(...)
.collectList(),
repo3
.saveAll(...)
.collectList())
.map(this::createSpecificObject))
.doOnNext(item-> createObjAndCallAnotherService(item));
}
private void createObjAndCallAnotherService(Prot prot){
myRepository
.findById(
prot.getDomCred().stream()
.filter(Objects::nonNull)
.findFirst()
.map(ConfDomCred::getCredId)
.orElse(UUID.fromString("00000000-0000-0000-0000-000000000000")))
.doOnNext( //one value is returned from myRepository -> Flux<MyObjectWithNeededData>
confCred-> {//from this point the code is unreachable!!! - why????
Optional<ConfDomCred> confDomCred=
prot.getDomCreds().stream().filter(Objects::nonNull).findFirst();
confDomCred.ifPresent(
domCred -> {
ProtComDto com=
ProtComDto.builder()
.userName(confCred.getUsername())
.password(confCred.getPassword())
.build();
clientApiToAnotherService.callEndpintInAnotherService(com); //this is a client like Feign that invokes method in another service
});
});
}
UPDATE
When I invoke
Flux<MyObj> myFlux = myRepository
.findById(
prot.getDomCred().stream()
.filter(Objects::nonNull)
.findFirst()
.map(ConfDomCred::getCredId)
.orElse(UUID.fromString("00000000-0000-0000-0000-000000000000")));
myFlux.subscribe(e -> e.getPassword())
then the value is printed
UPDATE2
So as a recap - I think the code below is asynchronous/non-blocking - am I right?
In my
ProtectionCommandService
I had to use subscribe() twice - only then I can call my other service and store them my object: commandControllerApi.createNewCommand
public Mono<Protection> saveProtection(Mono<Protection> newProtection) {
return newProtection.flatMap(
protection ->
Mono.zip(
protectorRepository.save(//some code),
domainCredentialRepository
.saveAll(//some code)
.collectList(),
protectionSetRepository
.saveAll(//some code)
.collectList())
.map(this::createNewObjectWrapper)
.doOnNext(protectionCommandService::createProtectionCommand));
}
ProtectionCommandService class:
public class ProtectionCommandService {
private final ProtectionCommandStrategyFactory protectionCommandFactory;
private final CommandControllerApi commandControllerApi;
public Mono<ProtectionObjectsWrapper> createProtectionCommand(
ProtectionObjectsWrapper protection) {
ProductType productType = protection.getProtector().getProductType();
Optional<ProtectionCommandFactory> commandFactory = protectionCommandFactory.get(productType);
commandFactory
.get()
.createCommandFromProtection(protection)
.subscribe(command -> commandControllerApi.createNewCommand(command).subscribe());
return Mono.just(protection);
}
}
And one of 2 factories:
#Component
#AllArgsConstructor
#Slf4j
public class VmWareProtectionCommandFactory implements ProtectionCommandFactory {
private static final Map<ProductType, CommandTypeEnum> productTypeToCommandType =
ImmutableMap.of(...//some values);
private final ConfigurationCredentialRepository configurationCredentialRepository;
#Override
public Mono<CommandDetails> createCommandFromProtection(ProtectionObjectsWrapper protection) {
Optional<DomainCredential> domainCredential =
protection.getDomainCredentials().stream().findFirst();
return configurationCredentialRepository
.findByOwnerAndId(protection.getOwner(), domainCredential.get().getCredentialId())
.map(credential -> createCommand(protection, credential, domainCredential.get()));
}
and createCommand method returns Mono object as a result of this factory.
private Mono<CommandDetails> createCommand(Protection protection
//other parameters) {
CommandDto commandDto =
buildCommandDto(protection, confCredential, domainCredentials);
String commands = JsonUtils.toJson(commandDto);
CommandDetails details = new CommandDetails();
details.setAgentId(protection.getProtector().getAgentId().toString());
details.setCommandType(///some value);
details.setArguments(//some value);
return Mono.just(details);
UPDATE3
My main method that calls everything has been changed a little bit:
public Mono<MyObj> saveObj(Mono<MyObj> obj) {
return obj
.flatMap(
ob->
Mono.zip(
repo1.save(
...),
repo2
.saveAll(...)
.collectList(),
repo3
.saveAll(...)
.collectList())
.map(this::wrapIntoAnotherObject)
.flatMap(protectionCommandService::createProtectionCommand)
.map(this::createMyObj));
Stop breaking the chain
This is a pure function it returns something, and always returns the same something whatever we give it. It has no side effect.
public Mono<Integer> fooBar(int number) {
return Mono.just(number);
}
we can call it and chain on, because it returns something.
foobar(5).flatMap(number -> { ... }).subscribe();
This is a non pure function, we can't chain on, we are breaking the chain. We can't subscribe, and nothing happens until we subscribe.
public void fooBar(int number) {
Mono.just(number)
}
fooBar(5).subscribe(); // compiler error
but i want a void function, i want, i want i want.... wuuaaa wuaaaa
We always need something to be returned so that we can trigger the next part in the chain. How else would the program know when to run the next section? But lets say we want to ignore the return value and just trigger the next part. Well we can then return a Mono<Void>.
public Mono<Void> fooBar(int number) {
System.out.println("Number: " + number);
return Mono.empty();
}
foobar(5).subscribe(); // Will work we have not broken the chain
your example:
private void createObjAndCallAnotherService(Prot prot){
myRepository.findById( ... ) // breaking the chain, no return
}
And some other tips:
Name your objects correctly not MyObj and saveObj, myRepository
Avoid long names createObjAndCallAnotherService
Follow single responsibility createObjAndCallAnotherService this is doing 2 things, hence the name.
Create private functions, or helper functions to make your code more readable don't inline everything.
UPDATE
You are still making the same misstake.
commandFactory // Here you are breaking the chain because you are ignoring the return type
.get()
.createCommandFromProtection(protection)
.subscribe(command -> commandControllerApi.createNewCommand(command)
.subscribe()); // DONT SUBSCRIBE you are not the consumer, the client that initiated the call is the subscriber
return Mono.just(protection);
What you want to do is:
return commandFactory.get()
.createCommandFrom(protection)
.flatMap(command -> commandControllerApi.createNewCommand(command))
.thenReturn(protection);
Stop breaking the chain, and don't subscribe unless your service is the final consumer, or the one initiating a call.
I'm struggling to come up with an RXJava2 Solution to "a simple problem". I am not extremely experienced with RXJava beyond the simple use cases.
Suppose I have a Container that looks like:
class Container {
List<A> listOfA;
}
The rest of the model is a series of nested lists like this model:
class Base {
// irrelevant content
}
class A extends Base {
List<B> listOfB;
}
class B extends Base {
// irrelevant content
}
Somewhere in my code, I obtain a Single<Container> like so:
(note: the code/types/etc have been obfuscated/simplified for an easier reading)
disposables = new CompositeDisposable(); // not important here
disposables.add(
interactor.getTheContainer() // This returns a Single<Container>
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<Container>() {
// on error ommited for clarity
#Override
public void onSuccess(final Container value) {
process(value);
}
})
);
private void process(final Container container) {
List<Base> items = new ArrayList<>();
List<A> listOfA = container.getListOfA();
for (A a : listOfA) {
items.add(a);
items.addAll(a.getListOfB());
}
// do something with "items" - ommited for clarity
}
I have been unsuccessfully trying to convert the method process(Container) to RXJava (maybe I shouldn't but now I want to know).
I can't even begin to list all the stuff I've experimented with, but I'm really new to RXJava 2 (most usages I've done in the past years with RX were simple Observables from Retrofit and nothing too fancy, or even as an Event Bus to replace Otto/Guava), so I am really not well versed in the arts of making good usage of the RX toolset. I think some sort of map should work, but the whole Java syntax gets confusing really fast for me when it comes to anonymous methods.
The question is:
Where should I read/look for ideas how to perform the same operation of the process method but with RXJava2?
Order is important, the final list looks like this with the current method and I need it this way:
0. A1
1. B1.1
2. B1.2
3. B1.nn…
4. A2
5. B2.1
6. B2.2
7. B2.nn…
8. A3
9. B3.1
…
You get the idea.
Any hints? I do not have Retrolambda or Java 8 (nor can use it, it's not my decision and I can't do anything about it).
You were almost there:
List<Base> process(List<A> list) {
List<Base> result = new ArrayList<>();
for (A a : list) {
result.add(a);
result.addAll(a.getListOfB());
}
return result;
}
interactor.getTheContainer() // This returns a Single<Container>
.subscribeOn(Schedulers.io())
.map(new Function<Container, List<Base>>() {
#Override public List<Base> apply(Container c) {
return process(c.getListOfA());
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new DisposableSingleObserver<List<Base>>() {
#Override public void onSuccess(final List<Base> value) {
/* display the list */
}
})
A more "convoluted" solution could replace the map above with some Iterable transformation via IxJava:
.flatMapIterable(new Function<Container, Iterable<A>>() {
#Override public Iterable<A> apply(Container c) {
return c.getListOfA();
}
})
.flatMapIterable(new Function<Iterable<A>, Iterable<Base>>() {
#Override public Iterable<Base> apply(Iterable<A> a) {
return Ix.<Base>just(a).concatWith(a.getListOfB());
}
})
.toList()
How to create my own hot Observable from scratch?
I would like create my own function, returning observable, returning locations:
public static Observable<Location> locationObservable(Context context, String provider, long minTime, float minDistance) {
This is for Android. It is recommended to use Observable.create() for this purposes, but example shows just passing constant list of integers to each subscriber, which is not hot.
If I do something else here, for example, remember a list of subscribers, then how will I implement unsubscribing and many other features?
I.e. absolutely no idea is what to do inside Observable.OnSubscribe<Integer>() implementation?
Generally to create hot observable you use some kind of Subject: PublishSubject, BehaviorSubject, etc.
See examples for BehaviorSubject here.
class LocationService {
private Subject<Location> subject = BehaviorSubject.create();
Observable<Location> locationObservable(...) {
return subject;
}
void onNewLocationListener(Location newLocation) {
subject.onNext(newLocation);
}
}
It is not recommended to write your own, at least until you are proficient with the existing ones and need a peculiar caching/emission pattern not covered by the default 5 (Async, Behavior, Publish, Replay, Unicast).
I have a 3 part series on the subject (pun intended) if you really want to:
Part 1
Part 2
Part 3
Look at this wonderful example taken directly from Realm's RealmObservableFactory:
#Override
public Observable<Realm> from(Realm realm) {
final RealmConfiguration realmConfig = realm.getConfiguration();
return Observable.create(new Observable.OnSubscribe<Realm>() { // create new observable
#Override
public void call(final Subscriber<? super Realm> subscriber) { // this is executed on `subscribeOn(Scheduler)`
final Realm observableRealm = Realm.getInstance(realmConfig);
final RealmChangeListener<Realm> listener = new RealmChangeListener<Realm>() {
#Override
public void onChange(Realm realm) {
if (!subscriber.isUnsubscribed()) { // always check if subscriber is unsubscribed!
subscriber.onNext(observableRealm);
}
}
};
subscriber.add(Subscriptions.create(new Action0() { // add unsubscription first! thread specified by unsubscribeOn(Scheduler)
#Override
public void call() {
observableRealm.removeChangeListener(listener); // remove listener
observableRealm.close();
}
}));
observableRealm.addChangeListener(listener); // add listener
subscriber.onNext(observableRealm); // initial value
}
});
}
And read the comments, it's a pretty good example.
i am using RxAndroid/RxJava for the first time and trying to figure out how to implement a chain of requests but each next request made is dependent on the result of the other.
example:
private Boolean isUserEligible(){
..
}
private String registerDevice()
..
}
private String login(){
..
}
As far as i know, the Observable can only execute all of the above methods or one by one like below:
// Fetch from both simultaneously
Observable<String> zipped
= Observable.zip(isUserEligible(), registerDevice(),login(), new Func2<String, String, String>() {
});
Observable<String> concatenated = Observable.concat(isUserEligible(), registerDevice(),login());
what if i want to do something like this
//execute usUserEligible first and if eligible, execute registerDevice, else execute login().
Thanks in advance
Assuming all of these methods return observables, you could write:
Observable<String> response = isUserEligible()
.flatMap(isEligible -> isEligible ? registerDevice() : login());
Without retro-lambda; you could write:
Observable<String> response = isUserEligible()
.flatMap(new Func1<Boolean, Observable<String>>() {
public Observable<String> call(final Boolean isEligible) {
return isEligible ? registerDevice() : login();
}
});
This is a use case for a flatmap.
http://reactivex.io/documentation/operators/flatmap.html
Create the mapping from the first result to a second observable, here you can use the result of the first function to input it into the second.
final Func1<Boolean, Observable<String>> registerFunc = isEligible -> {
return registerDevice(isEligible)
};
Now you have to create your chain of calls and flatMaps: do the first call, and flatmap the resulting Observable with the function you just created. This will again return an Observable. you can keep chaining it here with other flatmaps
isUserEligible().flatMap(registerFunc);
Be aware that all your functions need to return Observables to make this possible.
Sorry, I'm new to Play Framework.
I use it with Java API.
Let's say I want to have a controller action that runs some kind of import and displays result after import is finished.
Import requires expensive HTTP communication with the 3rd party service (fetching data from 3 URLs, processing data, updating database after all 3 resources were processed).
So I'd like to implement an import itself as a Promise in controller (Controller shouldn't be aware of import implementation).
Then I'd like to run fetching the data from URLs and processing in 3 parallel threads. I think it would be nice to implement it as a 3 separate Promises.
Database should be updated only when (and if) all three promises were completed successfully.
And finally controller should be notified after database was updated.
I'm able to implement the whole import as a Promise, but I don't know how to implement nested promises.
Could you suggest how to implement it or correct me if I'm trying to use wrong approach?
You can achieve this with flatmap. The syntax in Java is sadly a bit clunky because of the anonymous interfaces (will get better with Java 8 and lambdas). Promise<T>.flatMap accepts a Function<T, Promise<U>> and will return a Promise<U>. This means you can nest flatMaps from all your three operations and collect them with a flatmap, like this:
final Promise<String> promise1 = Promise.pure("one");
final Promise<String> promise2 = Promise.pure("two");
final Promise<String> promise3 = Promise.pure("three");
Promise<String> allThreeCombined = promise1.flatMap(new Function<String, Promise<String>>() {
#Override
public Promise<String> apply(final String result1) throws Throwable {
return promise2.flatMap(new Function<String, Promise<String>>() {
#Override
public Promise<String> apply(final String result2) throws Throwable {
return promise3.map(new Function<String, String>() {
#Override
public String apply(String result3) throws Throwable {
return result1 + result2 + result3;
}
});
}
});
}
});
If there is no special meaning to each of the different things you are fetching - for example if they are to be treated as a list of values you can also use Promise.sequence() which accepts a list of Promise<T> and return a Promise<List<T>> so you can react on all values arriving.