In RX JAVA(java8), how can I persist value of previous flatMap or map.
public void createAccount(]) {
JsonObject payload = routingContext.getBodyAsJson();
socialService.getOAuthToken(payload)
.flatMap(token -> {
return getAllAccounts(token);
})
.flatMap(accounts -> {
// Save accounts with TOKENS
})
.subscribe(accountID -> {
response(accountID);
);
}
So in above code, in second flatMap how can I get the token from previous flatMap.
You have to zip account and token and pass it to the next Stream operation.
//Note you have to replace T, A with the right type
socialService.getOAuthToken(payload).flatMap(token -> getAllAccounts(token)
.map(account -> new SimpleImmutableEntry<T, A>(token, account)))
.flatMap(accounts -> /* accounts.getKey() -> token, accounts.getValue() -> account */)
.subscribe(accountId -> response(accountId));
Kotlin solution based on the solution by #Flown:
socialService.getOAuthToken(payload)
.flatMap { token ->
getAllAccounts(token)
.map { account -> Pair(token, account) }
}
.flatMap { (token, account) -> /* Use values here */ }
.subscribe { accountId -> response(accountId) }
Related
I want to use Context in my Flux pipe to bypass filtering.
Here's what I have:
public Flux<Bar> realtime(Flux<OHLCIntf> ohlcIntfFlux) {
return Flux.zip(
ohlcIntfFlux,
ohlcIntfFlux.skip(1),
Mono.subscriberContext().map(c -> c.getOrDefault("isRealtime", false))
)
.filter(l ->
l.getT3() ||
(!l.getT2().getEndTimeStr().equals(l.getT1().getEndTimeStr())))
.map(Tuple2::getT1)
.log()
.map(this::
}
which is input to this this:
public void setRealtime(Flux<Bar> input) {
Flux.zip(input, Mono.subscriberContext())
.doOnComplete(() -> {
...
})
.doOnNext(t -> {
...
})
.subscribe()
}
I can tell my code in ... is not failing, I can even access the Context map, but when the first iteration completes, I get:
onContextUpdate(Context1{reactor.onNextError.localStrategy=reactor.core.publisher.OnNextFailureStrategy$ResumeStrategy#35d5ac51})
and subscriber disconnects.
So my question is whether I am using it right and what can be an issue here?
EDIT:
I have tried to repeat() the Mono.subscriberContext() when I'm using value out of it:
return Flux.zip(
ohlcIntfFlux,
ohlcIntfFlux.skip(1),
Mono.subscriberContext()
.map(c -> c.getOrDefault("isRealtime", new AtomicBoolean())).repeat()
)
.filter(l ->
l.getT3().get() ||
(!l.getT2().getEndTime().isEqual(l.getT1().getEndTime())))
.map(Tuple2::getT1)
and set the AtomicBoolean to the context on the subscriber end and just change the value inside this variable reference, when I need the signal on the upstream, but it doesn't change at all:
input
.onErrorContinue((throwable, o) -> throwable.getMessage())
.doOnComplete(() -> {
System.out.println("Number of trades for the strategy: " + tradingRecord.getTradeCount());
// Analysis
System.out.println("Total profit for the strategy: " + new TotalProfitCriterion().calculate(timeSeries, tradingRecord));
})
.doOnNext(this::defaultRealtimeEvaluator)
.subscriberContext(Context.of("isRealtime", isRealtimeAtomic))
.subscribe();
at least with repeat the Flux doesn't disconnect but the value I'm getting out of it is not being updated. No other clues I have.
Spring-webflux: 2.1.3.RELEASE
this works:
input
.onErrorContinue((throwable, o) -> throwable.getMessage())
.doOnComplete(() -> { ... }
.flatMap(bar -> Mono.subscriberContext()
.map(c -> Tuples.of(bar, c)))
.doOnNext(this::defaultRealtimeEvaluator)
.subscriberContext(Context.of("isRealtime", new AtomicBoolean()))
.subscribe();
so the point is to set AtomicBoolean in my case as the cotnext and then extract this variable out of the context if you want to change it's value. the same on the upstream flux.
I have an API that returns a Single. This Single contains a list of values, let's say String values. When I am calling this object, I get that Single and have to filter some values from it and return back another Single. I'm trying to achieve something like in this simplified test:
#Test
public void filterTest() {
List<String> sourceList = Arrays.asList("email", "phone", "smoke", "email", "phone", "fax", "email");
Single.just(sourceList)
.toObservable()
.flatMap(source -> {
return Observable.from(source);
})
.filter(source -> !source.equals("email"))
.groupBy(/* criteria? */)
//how to extract single list from groupBy or
//is there another opposite function for flatMap?
.toSingle()
.subscribe(s -> System.out.println(s));
}
Try this:
Single.just(sourceList)
.flattenAsObservable(source -> source)
.filter(source -> !source.equals("email"))
.toList()
.subscribe(s -> System.out.println(s));
or
Observable.fromIterable(sourceList)
.filter(source -> !source.equals("email"))
.toList()
.subscribe(s -> System.out.println(s));
I am new in concept of RxJava.
I would like to chain some calls:
Observable<RoomList> listRoomsCall = mRoomServiceApi.listRooms();
//This call will get me RoomIds
Next step is to call for all RoomIds - request after request
mMeetingServiceApi.listMeetings(roomID, startsAtString, endsAtString, free))
How should I chain first call with next calls?
I thinkt that I should use flatMap and loop to call all requets but how to connect all responses on the end?
listRoomsCall.flatMap(v -> {
for (ExchangeRoom exchangeRoom : v.getExchangeRoomList()) {
mMeetingServiceApi.listMeetings(roomID, startsAtString, endsAtString, free);
}
})
Turn the inner list into an Observable and flatMap over it again:
listRoomsCall
.flatMapIterable(v -> v.getExchangeRoomList())
.flatMap(exchangeRoom -> {
mMeetingServiceApi.listMeetings(roomID, startsAtString, endsAtString, free);
})
.subscribe(/* */);
or
listRoomsCall
.flatMap(v ->
Observable.fromIterable(v.getExchangeRoomList())
.flatMap(exchangeRoom -> {
mMeetingServiceApi.listMeetings(roomID, startsAtString, endsAtString, free);
})
)
.subscribe(/* */);
I have the following the code currently.
Method - parseGreeting()
public GetGreetingNmsObjects parseGreeting(String greetingType, GetGreetingNmsResponse xmlFromNms) {
GetGreetingNmsObjects objectFound = null;
List<GetGreetingNmsObjects> objList = xmlFromNms.getObject();
for (GetGreetingNmsObjects obj : objList) {
List<Attribute> attrs = obj.getAttributes();
Optional<Boolean> found = attrs.stream()
.filter(a -> a.name.equals(GREETING_TYPE))
.map(a -> a.value.equals(greetingType))
.findAny();
if(found.get()) {
objectFound = obj;
break;
}
return objectFound;
}
GetGreetingNmsObjects .java
public class GetGreetingNmsObjects {
List<Attribute> attributeList;
public List<Attribute> getAttributes() {
return attributeList;
}
}
In the above method, is there a way to avoid the for loop and if statement and handle with streams itself?
I tried to use 'flatmap' and get the stream for 'attributesList' but once the match is found, I could not get reference to 'GetGreetingNmsObjects' object.
GetGreetingNmsObjects objectFound = objList.stream()
.flatMap(grt -> grt.getAttributes())
.filter(a -> a.name.equals(GREETING_TYPE))
.map(a -> a.value.equals(greetingType))
????
Your original code contains a logic error:
Optional<Boolean> found = …
.map(a -> a.value.equals(greetingType))
.findAny();
This will return the result of an arbitrary comparison, in a sequential context, it’s likely the result of the first element.
I’m quite sure that you actually want to know whether there is any matching element, hence, should use
boolean found = …
.anyMatch(a -> a.value.equals(greetingType));
This can be simply used as predicate to find the first element having the matching element:
return xmlFromNms.getObject().stream()
.filter(obj -> obj.getAttributes().stream()
.filter( a -> a.name.equals(GREETING_TYPE))
.anyMatch(a -> a.value.equals(greetingType)))
.findFirst().orElse(null);
I'd like to know if there is a good way of reusing a common stream operation that varies in the end for different outputs.
The example bellow is exactly what I'm trying to compact into a one-step operation:
public static DepartmentInfo extractDepartmentInfo(BaselinePolicy resource) throws ResourceProcessorError {
Function<Exception, Exception> rpe = e -> new ResourceProcessorError(e.getMessage());
List<String> parents =
Objects.requireNonNull(
Exceptions.trying(
() -> Arrays.asList(Exceptions.dangerous(resource::getParentIds).expecting(CMException.class).throwing(rpe))
.stream()
.map(cId -> Exceptions.dangerous(cId, resource.getCMServer()::getPolicy).expecting(CMException.class).throwing(rpe))
.filter(policy -> PagePolicy.class.isAssignableFrom(policy.getClass()))
.map(PagePolicy.class::cast)
.filter(page -> Exceptions.dangerous(page,
p -> Boolean.valueOf(p.getComponentNotNull(ComponentConstants.POLOPOLY_CLIENT,
ComponentConstants.IS_HOME_DEPARTMENT,
Boolean.FALSE.toString())).booleanValue())
.expecting(CMException.class).throwing(rpe))
.map(page -> Exceptions.dangerous(page, p -> p.getExternalId().getExternalId()).expecting(CMException.class).throwing(rpe)), ResourceProcessorError.class)
.collect(Collectors.toList()));
String externalId = parents.get(parents.size()-1).toString();
List<String> list =
Objects.requireNonNull(
Exceptions.trying(
() -> Arrays.asList(Exceptions.dangerous(resource::getParentIds).expecting(CMException.class).throwing(rpe))
.stream()
.map(cId -> Exceptions.dangerous(cId, resource.getCMServer()::getPolicy).expecting(CMException.class).throwing(rpe))
.filter(policy -> PagePolicy.class.isAssignableFrom(policy.getClass()))
.map(PagePolicy.class::cast)
.map(page ->
Exceptions.dangerous(page,
p -> p.getChildPolicy(PATH_SEGMENT) != null &&
StringUtils.hasLength(SingleValued.class.cast(p.getChildPolicy(PATH_SEGMENT)).getValue())?
SingleValued.class.cast(p.getChildPolicy(PATH_SEGMENT)).getValue(): p.getName()).expecting(CMException.class).throwing(rpe))
.filter(val -> val != null && !val.isEmpty()), ResourceProcessorError.class)
.collect(Collectors.toList()));
if(list.size() > 3) {
list = list.subList(list.size() - 3, list.size()-1);
}
switch(list.size()) {
case 0: {
throw new ResourceProcessorError("br.com.oesp.XMLRender.error.noProduct");
}
case 1: {
return DepartmentInfo.withProduct(list.get(0), externalId);
}
case 2: {
return DepartmentInfo.withProduct(list.get(0), externalId).withDepartment(list.get(1));
}
default: {
return DepartmentInfo.withProduct(list.get(0), externalId).withDepartment(list.get(1)).withSubDepartment(list.get(2));
}
}
}
Notice that the first step is repeated for both:
List<String> parents =
Objects.requireNonNull(
Exceptions.trying(
() -> Arrays.asList(Exceptions.dangerous(resource::getParentIds).expecting(CMException.class).throwing(rpe))
.stream()
.map(cId -> Exceptions.dangerous(cId, resource.getCMServer()::getPolicy).expecting(CMException.class).throwing(rpe))
.filter(policy -> PagePolicy.class.isAssignableFrom(policy.getClass()))
.map(PagePolicy.class::cast)
It's not only a problem for reading but specially because I'm redoing a heavy operation twice, meanwhile in a more imperative way I'd do it once.
There are two things you're trying to do:
avoid the redundant work of creating the input array
avoid the redundant code of the map/filter/map
The first is easy:
List<Id> list = Arrays.asList(Exceptions.dangerous(resource::getParentIds)
.expecting(CMException.class)
.throwing(rpe));
Now you can pull streams from this source twice without rematerializing it.
The next bit is simply a Function from List to Stream:
Function<List<Id>, Stream<Something>> asStream =
list -> list.stream().map(...).filter(...).map(...);
Now, just start your stream with this:
asStream.apply(list).moreStuff().moreStuff()