Convert Mono<Stream<String>> to Flux<String> - java

I have a Mono like this Mono<Stream<String>> and I want to convert it to a Flux like this Flux<String>. In my junior mind I think it should be simple because Mono<Stream<String>> is the "hope" for a String and Flux<String> is also the "hope" of a String, therefore there should be a simple operator to do the conversion.
I am new to Spring boot webflux, so if there is an operator for this query just show me or tell me why such operation is not possible.
Mono<Stream<String>> authoritiesStream = Mono.just(Stream.of(""));
Flux<String> authorities = authoritiesStream.???
I don't want to collect() the stream and use flatMapIterable() to do the conversion because collecting would imply that I have lost my asynch edge. Please teach me
Thank you in advance.

Not sure what is the idea behind Mono<Stream<String>> but assuming you are getting it from another method you could do something like
Flux<String> authorities = authoritiesStream
.flatMapMany(stream -> Flux.fromStream(stream));

Related

apache commons: FailableFunction and Function inside same FailableStream

Is there any way to use both FailableFunction and Function lambdas into a single .map chaining stream?
Function<String, Organization> hook = (id) -> this.organizationRepository.findById(id).get();
FailableFunction<Organization, Organization, MpiException> failableSave = (r) -> this.organizationRepository.save(r);
List<String> ids;
Failable.stream(ids)
.map(hook)
.map(failableSave)
.collect(Collectors.toList());
I'm getting:
The method map(FailableFunction<String,R,?>) in the type Streams.FailableStream is not applicable for the arguments (Function<String,Organization>)
Problem here is that sometimes I need to use Function and other times I need to use FailableFunction.
Any ideas about how to use them into same stream mapping chaining?
Maybe not the most elegant solution, but since nobody else came up with something:
You could use a method reference to implicitly convert a Function into a FailableFunction:
Failable.stream(ids)
.map(hook::apply)
.map(failableSave)
.collect(Collectors.toList());

how to avoid .flatMap(x-> reactiveAction(x).thenReturn(x))

During some reactive programming in Java using project reactor library, I stumbled upon a pattern for which I'm wondering if there is out of box support?
So I want the code below:
Mono.just("hello")
.flatMap(hello -> reactiveAction(hello).thenReturn(hello))
..
.;
to be turned into something like:
Mono.just("hello")
.coolOperation(this::reactiveAction)
..
.;
I can not use doOnNext because what I want to do inside reactiveAction is not side effect.
and reactive action is:
Mono<Integer> reactiveAction(String text){
return ....
}
Have you considered Mono#delayUntil?
Mono.just("hello")
.delayUntil(hello -> reactiveAction(hello))
..
.;
I can't find built-in solution, but you could create utility function:
public static <T> Function<Mono<T>, Publisher<T>> coolOperation(
Function<T, Mono<?>> companionMonoFunction) {
return originalMono -> originalMono
.flatMap(t -> companionMonoFunction.apply(t)
.thenReturn(t));
}
And now you can use it with transform or transformDeffered:
Mono.just("hello")
.transform(coolOperation(this::reactiveAction))
...;
But for me it doesn't look much prettier :)
EDIT: see #bsideup answer, looks like delayUntil could fit the bill.
My original answer as an alternative suggestion:
I don't think there is any baked-in syntactic sugar to do this, as the "perform an async operation that depends on the original onNext" is the very definition of flatMap. We actually added the thenReturn(foo) as syntactic sugar over .then(Mono.just(foo)).
If you want to further shorten the code, offer an alternative to reactiveAction that also returns the original value:
Mono<String> reactiveActionBackground(String text){
return reactiveAction(text).thenReturn(text);
}
which can then be invoked directly on flatMap rather than through transform:
Mono.just("hello")
.flatMap(this::reactiveActionBackground);

Better approach for stream filter in Java

Is there a way to simplify filter using stream?
Or for it to be shorter or optimized? I'm not quite sure if using a for loop would be better to use in this scenario.
I'm just trying to separate the failed and the success messages using the failedIds.
Here is my code
List<Message> successMessages = messageList.stream()
.filter(message -> !failedMessageIds.contains(message.getId()))
.collect(Collectors.toList());
List<Message> failedMessages = messageList.stream()
.filter(message -> failedMessageIds.contains(message.getId()))
.collect(Collectors.toList());
Thank you!
You may use groupingBy collector here. This solution passes over the collection only once. Also make sure to use a Set for failedMessageIds.
Map<Boolean, List<Message>> messagesByStateMap = messageList.stream()
.collect(Collectors.groupingBy(m -> !failedMessageIds.contains(m.getId())));
List<Message> successMessages = messagesByStateMap.get(true);
A much better approach would be to use the partitioningBy collector as stated in the following comment since your classifier function is a just a Predicate.
Map<Boolean, List<Message>> messagesByStateMap = messageList.stream()
.collect(Collectors.partitioningBy(m -> !failedMessageIds.contains(m.getId())));
However, since the use of streams has sparked some controversy, here's the equivalent iterative solution using Java 8.
for (Message message : messageList)
messagesByStateMap.computeIfAbsent(!failedMessageIds.contains(message.getId()),
unused -> new ArrayList<>())
.add(message);

How to convert List<Mono<String>> into Flux<List<String>>?

List<Mono<String>> responses = apiCall()
I would like to get Flux<String> to await all mono-s from list.
How could I achieve it ?
P.S.
I've found similar question but I need vice versa operation https://stackoverflow.com/a/44040346/2674303
You could use Flux.mergeSequential() and Flux.collectList()
Mono<List<String>> list = Flux.mergeSequential(apiCall()).collectList();

Can Java 8 Streams use multiple items from mapping pipeline

I have some data stored in a JPA Repository that I am trying to process. I would like to be able to use Java 8 Streams to do so, but can not figure out how to get the required information. This particular 'Entity' is actually only for recovery, so it holds items that would need to be processed after something like a power-fail/restart.
Using pre-Java 8 for-loops the code would look like:
List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
for (MyEntity item : deletes) {
String itemJson = item.getData();
// use a Jackson 'objectMapper' already setup to de-serialize
MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
processDelete(deleteEvent, item.getId());
}
The problem arises from the two parameter method called at the very end. Using Streams, I believe I would do:
// deletes.stream()
// .map(i -> i.getData())
// .map(event -> objectMapper.readValue(event, MyEventClass.class))
// .forEach(??? can't get 'id' here to invoke 2 parameter method);
I have a solution (without Streams) that I can live with. However I would think this problem comes up a lot, thus my question is: IN GENERAL, is there a way using Streams to accomplish what I am trying to do?
Why not a Pair return on your map operation:
.map(i -> new Pair<>(i.getData(), i.getId()))
.map(pair -> new Pair<>(objectMapper.readValue(pair.getLeft(), MyEventClass.class), pair.getRight())
.forEach(p -> processDelete(pair.getLeft(), pair.getRight()))
I did not compile this, so there might be minor things to fix. But in general, you would need a Holder to pass your objects to the next stage in such a case. Either a Pair or some type or even a array.
Why not doing it simply this way?
deletes.forEach(item ->
processDelete(objectMapper.readValue(item.getData(), MyEventClass.class),
item.getId()));
This is a start at least, I guess it is dependent on why you want to use stream and how much you want to make it more functional
List<MyEntity> deletes = myEntityJpaRepository.findByDeletes();
deletes.stream().foreach(item -> {
String itemJson = item.getData();
// use a Jackson 'objectMapper' already setup to de-serialize
MyEventClass deleteEvent = objectMapper.readValue(itemJson, MyEventClass.class);
processDelete(deleteEvent, item.getId());
});

Categories

Resources