Fetching a list with Lagom framework - java

I'm VERY new to Lagom framework and I have absolutely no idea what I'm doing. I have a simple CRUD lagom application that does work, but I can't figure out how to retrieve a list.
So this is what I have for now, but I'm getting
#Override
public ServiceCall<NotUsed, Source<Movie, ?>> getMovies() {
return request -> {
CompletionStage<Source<Movie, ?>> movieFuture = session.selectAll("SELECT * FROM movies")
.thenApply(rows -> rows.stream()
.map(row -> Movie.builder()
.id(row.getString("id"))
.name(row.getString("name"))
.genre(row.getString("genre"))
.build()));
//.thenApply(TreePVector::from));
//.thenApply(is -> is.collect(Collectors.toList()))
return movieFuture;
};
}
but I'm getting a [Java] Type mismatch: cannot convert from Stream<Object> to Source<Movie,?> error on the rows.stream() line.
Any help would be appreciated.
Thanks in advance.

It looks like the return type should be a Source (from Akka Reactive Streams) but you are building a Java 8 Stream.
The problem can be easily solved if you used select instead of selectAll when querying the database. Lagom's CassandraSession provides two families of meqthods to query the DB: (1) select(...) will immediately return a Source<Row,NotUsed> which is a reactive stream or (2) selectAll(...) which will gather all rows in memory and return a List<Row>. The latter could take your server down because will try to put all the info in memory. The former will use reactive streams to deliver items adapting the speed to your consuming end speed (backpressure) keeping a very low memory footprint.
Your code can be rewritten as:
public ServiceCall<NotUsed, Source<GreetingMessage, ?>> getGreetings() {
return request ->
CompletableFuture.completedFuture(
session.select("SELECT * FROM greetings")
.map(row -> new GreetingMessage(row.getString(0)))
);
}
Using select creates a Source<>. You can map items individually on that Source<> using the lambda you already developed.

Related

Mutiny - Discarding Failures when Combining Results of Several Unis

I'm using Mutiny to try to fetch data from several external sources. Each call produces a list of results, and I am currently combining these results into one list in a Uni as follows:
List<Uni<List<Result>>> unis = new ArrayList<>();
for (Source source : sources) {
unis.add(source.getResults());
}
return Uni.combine().all().unis(unis).combinedWith(
responses -> {
List<Result> res = new ArrayList<>();
for (List<Result> response : (List<List<Result>>) responses) {
res.addAll(response);
}
return res;
}
);
When one of these Unis fails, though, the entire final Uni fails.
I want to be able to get the combined list of results from all of the calls that do not fail, and just log failures or something, but I can't figure out how to do this from the Mutiny documentation. Any help would be much appreciated.
You should have an error-handling strategy for each Uni then, so the combination only sees succeeeding Uni.
See:
https://quarkus.io/blog/mutiny-failure-handling/
https://smallrye.io/smallrye-mutiny/2.0.0/tutorials/handling-failures/

Conversion from Observable to Mono in Kotlin

Trying to insert in couchbase and that has observable return type but want mono,hence did this.
Its compiling but at run time its getting stuck forever at the conversion stage (i.e Mono.from { obs }).
fun saveScopeId(scopeId: ScopeId): Mono<ScopeId> {
val obs = scopeRepository.couchbaseOperations.insert(scopeId)
return Mono.from<ScopeId> { obs }
}
Observable can generate multiple values but if you can guarantee that it will be one item (I assume this is why you want to use Mono here) you can use Mono.fromDirect in this way:
Mono.fromDirect(yourObservable.toFlowable(BackpressureStrategy.BUFFER));
As you can see in example, there is toFlowable method used.
You should see the other backpressure strategies: here
This way we can achieve but not sure about the performance part.
As there Rx -> Rx -> Reactor conversion. Can someone tell me by looking into couchbase SDK 4.x (introduced recently), only if there are some conversion issue.
Mono.fromDirect(RxReactiveStreams.toPublisher(scopeRepository.couchbaseOperations.insert(scope)))
Try this but this thread blocking model.
public Mono<String> GetData(Observable<String> inputData) {
return Mono.fromCallable(() -> inputData.blockingFirst(""));
}

Can I create a list using streams where the critera are to check one list then add an object to another list?

Is there a more elegant way to do this using streams, in java 8?
Can you give me some tips on what parts of the documentation I should look at?
I thought it might be possible to do this without creating the empty featureList first, but I can't get it to work.
There are two levels of features here, generic features that are available across all devices, and features that are enabled specifically on this device, since even though they are available, they can switched off for specific devices if we desire.
public List<DeviceFeature> getAllEnabledFeatures(DeviceID deviceId){
List<String> featureNames = getAllEnabledDeviceFeatures(deviceId);
List<DeviceFeature> featureList = new ArrayList<>();
featureNames.forEach(featureName -> {
DeviceFeature feature = getDeviceFeatureEnabledForDevice(featureName, deviceId);
if(feature != null) featureList.add(feature);
});
return featureList;
}
You don't need forEach, you can create a list directly by mapping featureNames:
return getAllEnabledDeviceFeatures(deviceId)
.stream()
.map(featureName ->
getDeviceFeatureEnabledForDevice(featureName, deviceId))
.filter(Objects::nonNull)
.collect(Collectors.toList());

Writing unit tests for Java 8 streams

I have a list and I'm streaming this list to get some filtered data as:
List<Future<Accommodation>> submittedRequestList =
list.stream().filter(Objects::nonNull)
.map(config -> taskExecutorService.submit(() -> requestHandler
.handle(jobId, config))).collect(Collectors.toList());
When I wrote tests, I tried to return some data using a when():
List<Future<Accommodation>> submittedRequestList = mock(LinkedList.class);
when(list.stream().filter(Objects::nonNull)
.map(config -> executorService.submit(() -> requestHandler
.handle(JOB_ID, config))).collect(Collectors.toList())).thenReturn(submittedRequestList);
I'm getting org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
LinkedList$$EnhancerByMockitoWithCGLIB$$716dd84d cannot be returned by submit() error. How may I resolve this error by using a correct when()?
You can only mock single method calls, not entire fluent interface cascades.
Eg, you could do
Stream<Future> fs = mock(Stream.class);
when(requestList.stream()).thenReturn(fs);
Stream<Future> filtered = mock(Stream.class);
when(fs.filter(Objects::nonNull).thenReturn(filtered);
and so on.
IMO it's really not worth mocking the whole thing, just verify that all filters were called and check the contents of the result list.

RXAndroid: get List objects from the difficult List

I have been trying for a long time to execute this code on Android, looking for answers here but not successfully. I'm a beginner developer, and please understand me.
I make multiple requests using Retrofit2 and RXJava
There is the answer, JSON (Array), it's class CurrencyData in Java
[
{
"r030":978,"txt":"euro","rate":11.11111,"cc":"EUR","exchangedate":"25.09.2018"
}
]
MyAPI interface
#GET("/BankService/v1/statdirectory/exchange")
Observable<List<CurrencyData>> getCurrencyCodeDate(#Query("valcode") String valCode, #Query("date") String date);
collect requests
List<Observable<List<CurrencyData>>> requests = new ArrayList<>();
requests.add(myApi.getCurrencyCodeDate("USD","20180928"));
requests.add(myApi.getCurrencyCodeDate("EUR","20180928"));
execute requests
Observable
.zip(requests, Arrays::asList)
.toList()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
I got
[[CurrencyData{txt='Dollar USA', rate='1.111'}], [CurrencyData{txt='EURO', rate='2.222'}]]
I'm interested in how to get a List<CurrencyData> with all the CurrencyData objects.
I tried to use map and flatMap - but it does not work.
I will be very grateful.
Thank you.
Problem:
Your getCurrencyCodeDate method returns Observable of List<CurrencyData>, And you are using it inside a Observable.zip() whith zipper func as Arrays::asList.
What is happening is, Your getCurrencyCodeDate emits a List of objects and Arrays::asList is wrapping all the emitted Lists in a List. Resulting in Observable.zip() emitting List<List<>>.
On top of that .toList() operator is applied, which will again wrap emitted List<List<>> inside another List resulting in List<List<List<>>> as return type.
What you could do is, use merge operator instead of zip and use collectInto instead of toList.
Observable
.merge(requests)
.collectInto(new ArrayList<CurrencyData>(), ArrayList::addAll)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

Categories

Resources