Converting Mono to Pojo without block - java

Is there a way to convert Mono objects to java Pojo?
I have a web client connecting to 3rd party REST service and instead of returning Mono I have to extract that object and interrogate it.
All the examples I have found return Mono<Pojo> but I have to get the Pojo itself. Currently, I am doing it by calling block() on Pojo but is there a better way to avoid block?
The issue with the block is that after few runs it starts throwing some error like block Terminated with error.
public MyPojo getPojo(){
return myWebClient.get()
.uri(generateUrl())
.headers(createHttpHeaders(headersMap))
.exchange()
.flatMap(evaluateResponseStatus())
.block();
}
private Function<ClientResponse, Mono<? extends MyPojo>> evaluateResponseStatus() {
return response -> {
if (response.statusCode() == HttpStatus.OK) {
return response.bodyToMono(MyPojo.class);
}
if (webClientUtils.isError(response.statusCode())) {
throw myHttpException(response);
// This invokes my exceptionAdvice
// but after few runs its ignored and 500 error is returned.
}
return Mono.empty();
};
}

It's not a good idea to block to operate on value in a reactive stream. Project Reactor offers you a selection of operators for you to handle the objects within a stream.
In your case, you can write getPojo() method like:
public Mono<MyPojo> getPojo() {
return myWebClient.get()
.uri(generateUrl())
.headers(createHttpHeaders(headersMap))
.retrieve()
.onStatus(status -> webClientUtils.isError(status),
response -> Mono.error(myHttpException(response))
.bodyToMono(MyPojo.class)
}
Note that using onStatus method, we replaced the whole evaluateResponseStatus method in your example.
You would use this method like the following:
// some method
...
getPojo()
.map(pojo -> /* do something with the pojo instance */)
...
I strongly advise you to look into Transforming an existing sequence in Project Reactor docs.

Since Webclient.block() is not recommended, the other way to retrieve the values from incoming httpresponse is to create a POJO in the calling application having the required fields. Then once the Mono is received, use Mono.subscribe(), within subscribe add a lambda function, with input say x, to retrieve the individual fields using the x.getters(). The values could be printed on console or assigned to a local var for further processing. This helps in two ways:-
Avoid the dreaded .block()
Keep the call Asynchronous when pulling large volumes of data.
This is one of many other ways to achieve the desired outcome.

Related

How do I pass an object to the next flow from a flow in spring integration?

Here I have 3 different flows and I'm using spring integration dsl. Let's assume we have prepared an object in flow 1 and I want to pass that object to other flows without disturbing the actual payload that's coming from the gateway. So I just want to add the object somehow in somewhere but not changing the actual payload so that I can use that object in subsequent flows. I can pass that in header but will that be correct to send a big object in header?
Here I'm using scatter gather pattern with three parallel flows.
#Bean
public IntegrationFlow flow() {
return flow ->
flow.handle(validatorService, "validateRequest")
.split()
.channel(c -> c.executor(Executors.newCachedThreadPool()))
.scatterGather(
scatterer ->
scatterer
.applySequence(true)
.recipientFlow(flow1())
.recipientFlow(flow2())
.recipientFlow(flow3()),
gatherer ->
gatherer
.releaseLockBeforeSend(true)
.releaseStrategy(group -> group.size() == 2))
.aggregate(lionService.someMethod())
// here I want to call other Integration flows
.gateway(someFlow())
.to(someFlow2());
}
//Here in this flow I'm calling prepareCDRequestFromLionRequest method in the handle(). This method returns an object1 which is one of the payload(among 3) that will be used after aggregation but I want to prepare another object2 in this method and somehow want to send that object2 to the someFlow() or someFlow2() but I want object1 as a payload.
#Bean
public IntegrationFlow flow1() {
return flow ->
flow.channel(c -> c.executor(Executors.newCachedThreadPool()))
.enrichHeaders(h -> h.errorChannel("flow1ErrorChannel", true))
.handle(cdRequestService, "prepareCDRequestFromLionRequest");
}
//same way I have flow2 and flow3
//validateRequest method
public Object1 validateRequest(LionRequest lionRequest) {
lionValidationHelper.validateRequestAttributes(lionRequest);
// validation code goes here after creating a new request object which will go to the parallel flows
Object1 obj1 = someLogicTocreateTheObject1
Object2 obj2 = someLogicTocreateTheObject2
return object1;
}
*UPDATE - Now as u see above I'm sending object1 as a payload but I need object2 to be sent from here somehow so that I can make use of this object2 in other subsequent flows. This Object2 is a POJO and having different fields so in other flows I'll be getting relevant information which I'll be setting to it's fields. And finally I'll be getting an object which then I'll be using in someFlow(). So I want object to be passed and enhancing that object in different flows that I have.
Or let's suppose after validateRequest I want to create an object and want to pass that to the parallel flows/someFlow somehow but I don't want to hamper the payload that will be coming to the flows. By using header it's achievable but is there a different way to achieve this?
We probably need to see your flows topology and more details about your solution, but there is indeed no problem to transfer big objects in the message headers.
You perhaps may also look into a publish-subscribe or recipient-list solution to send the same message to different sub-flows. This way you can do in those sub-flows whatever you need with request without looking into headers.
UPDATE
So, according your comment about scatter-gather, it sounds like you want to distribute a message to the recipients, gather their results and then continue together with an original, request message.
Since you say that you'd like do not send an extra header to those recipients, but still preserve a request message for post-gather processing, then you may look into a enrich() EI pattern, where your scatter-gather would be a request sub-flow. There you can decide to add a gather result into a header or property of the request payload (if that is possible).
See more info about Content Enricher in docs: https://docs.spring.io/spring-integration/docs/current/reference/html/message-transformation.html#payload-enricher

Why need to then Mono.empty() in the default implementation of generated Open API Spring code?

Here is the default implementation of an API generated by the openapi-generator-maven-plugin using Spring Boot as library:
default Mono<ResponseEntity<Void>> testAPI(
#Parameter(hidden = true) final ServerWebExchange exchange
) {
Mono<Void> result = Mono.empty();
exchange.getResponse().setStatusCode(HttpStatus.NOT_IMPLEMENTED);
return result.then(Mono.empty());
}
Being new to this, there are several things I don't understand:
There are two Mono.empty(), one being the result, one inside the then(Mono.empty()), why is it done like that?
Why can't it just returns one? e.g. return Mono.empty();
Or better yet, remove also the pass in exchange and just do:
return Mono.just(ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build());
The default implementation is more like a template that gives you a hint how to complete this API controller. For an API controller usually you need to create a response in at least two steps: first fetch data from some source and then make it a valid response. The template code can give you a start point to write such code. For example, I can write the following code using the template:
public class UsersApiController implements UsersApi {
#Override
public Mono<ResponseEntity<String>> usersGet(
#Parameter(hidden = true) final ServerWebExchange exchange
) {
var client = WebClient.create("http://calapi.inadiutorium.cz/");
Mono<String> result = client.get().uri("/api/v0/en/calendars/general-en/today").retrieve().bodyToMono(String.class);
return result.map(rep -> ResponseEntity.status(HttpStatus.OK).body(rep));
}
}
The first Mono.empty becomes the WebClient that gets data from another API, and the second Mono.empty is replaced by a map operation that transforms the API result to ResponseEntity object. If the generator only generates a Mono.empty, newcomers may feel difficult to start writing the controller.

Spring Webflux Proper Way To Find and Save

I created the below method to find an Analysis object, update the results field on it and then lastly save the result in the database but not wait for a return.
public void updateAnalysisWithResults(String uuidString, String results) {
findByUUID(uuidString).subscribe(analysis -> {
analysis.setResults(results);
computeSCARepository.save(analysis).subscribe();
});
}
This feels poorly written to subscribe within a subscribe.
Is this a bad practice?
Is there a better way to write this?
UPDATE:
entry point
#PatchMapping("compute/{uuid}/results")
public Mono<Void> patchAnalysisWithResults(#PathVariable String uuid, #RequestBody String results) {
return computeSCAService.updateAnalysisWithResults(uuid,results);
}
public Mono<Void> updateAnalysisWithResults(String uuidString, String results) {
// findByUUID(uuidString).subscribe(analysis -> {
// analysis.setResults(results);
// computeSCARepository.save(analysis).subscribe();
// });
return findByUUID(uuidString)
.doOnNext(analysis -> analysis.setResults(results))
.doOnNext(computeSCARepository::save)
.then();
}
Why it is not working is because you have misunderstood what doOnNext does.
Lets start from the beginning.
A Flux or Mono are producers, they produce items. Your application produces things to the calling client, hence it should always return either a Mono or a Flux. If you don't want to return anything you should return a Mono<Void>.
When the client subscribes to your application what reactor will do is call all operators in the opposite direction until it finds a producer. This is what is called the assembly phase. If all your operators don't chain together you are what i call breaking the reactive chain.
When you break the chain, the things broken from the chain wont be executed.
If we look at your example but in a more exploded version:
#Test
void brokenChainTest() {
updateAnalysisWithResults("12345", "Foo").subscribe();
}
public Mono<Void> updateAnalysisWithResults(String uuidString, String results) {
return findByUUID(uuidString)
.doOnNext(analysis -> analysis.setValue(results))
.doOnNext(this::save)
.then();
}
private Mono<Data> save(Data data) {
return Mono.fromCallable(() -> {
System.out.println("Will not print");
return data;
});
}
private Mono<Data> findByUUID(String uuidString) {
return Mono.just(new Data());
}
private static class Data {
private String value;
public void setValue(String value) {
this.value = value;
}
}
in the above example save is a callable function that will return a producer. But if we run the above function you will notice that the print will never be executed.
This has to do with the usage of doOnNext. If we read the docs for it it says:
Add behavior triggered when the Mono emits a data successfully.
The Consumer is executed first, then the onNext signal is propagated downstream.
doOnNext takes a Consumer that returns void. And if we look at doOnNext we see that the function description looks as follows:
public final Mono<T> doOnNext(Consumer<? super T> onNext)`
THis means that it takes in a consumer that is a T or extends a T and it returns a Mono<T>. So to keep a long explanation short, you can see that it consumes something but also returns the same something.
What this means is that this usually used for what is called side effects basically for something that is done on the side that does not hinder the current flow. One of those things could for instance logging. Logging is one of those things that would consume for instance a string and log it, while we want to keep the string flowing down our program. Or maybe we we want to increment a number on the side. Or modify some state somewhere. You can read all about side effects here.
you can of think of it visually this way:
_____ side effect (for instance logging)
/
___/______ main reactive flow
That's why your first doOnNext setter works, because you are modifying a state on the side, you are setting the value on your class hence modifying the state of your class to have a value.
The second statement on the other hand, the save, does not get executed. You see that function is actually returning something we need to take care of.
This is what it looks like:
save
_____
/ \ < Broken return
___/ ____ no main reactive flow
all we have to do is actually change one single line:
// From
.doOnNext(this::save)
// To
.flatMap(this::save)
flatMap takes whatever is in the Mono, and then we can use that to execute something and then return a "new" something.
So our flow (with flatMap) now looks like this:
setValue() save()
______ _____
/ / \
__/____________/ \______ return to client
So with the use of flatMap we are now saving and returning whatever was returned from that function triggering the rest of the chain.
If you then choose to ignore whatever is returned from the flatMap its completely correct to do as you have done to call then which will
Return a Mono which only replays complete and error signals from this
The general rule is, in a fully reactive application, you should never block.
And you generally don't subscribe unless your application is the final consumer. Which means if your application started the request, then you are the consumerof something else so you subscribe. If a webpage starts off the request, then they are the final consumer and they are subscribing.
If you are subscribing in your application that is producing data its like you are running a bakery and eating your baked breads at the same time.
don't do that, its bad for business :D
Subscribe inside a subscribe is not a good practise. You can use flatMap operator to solve this problem.
public void updateAnalysisWithResults(String uuidString, String results) {
findByUUID(uuidString).flatMap(analysis -> {
analysis.setResults(results);
return computeSCARepository.save(analysis);
}).subscribe();
}

How to chain reactive calls correctly and sequentially

I am trying to make calls with the following order:
save an object
publish an object creation event, only if the first step is done
Return a Flux list
What I have currently is following:
return dbSaveObject(object) //this returns Mono of created object
.doOnSuccess(s -> hermes.publishEvent(CREATE)) //publishEvent() here returns Mono<Void>
.thenMany(Flux.just(object))
Would this work and publish event as requested, or should I use zipWhen() instead of doOnSuccess()?
doOn... are so-called side-effect operators and should not be used for constructing reactive flows.
In case publishEvent returns Mono<Void> you could use the following
return dbSaveObject(object)
.flatMap(savedObject ->
hermes.publishEvent(CREATE)
.thenReturn(savedObject)
);

Returning single or multiple response in loop operations?

In my Java app, I have the following service method that calls another method and accumulate responses. Then returns these responses as a list. If there is not any exception, it works properly. However, it is possible to encounter exception for one of the call in the loop. In that case, it cannot return the previous responses retrieved until exception (if there are 10 process in the loop and there is an exception for the 6th process, then it cannot return the previous 5 responses added to the response list).
public List<CommandResponse> process(final UUID uuid) {
final Site site = siteRepository.findByUuid(uuid)
.orElseThrow(() -> new EntityNotFoundException(SITE_ENTITY_NAME));
// code omitted for brevity
for (Type providerType : providerTypeList) {
// operations
responses.add(demoService.demoMethod());
}
return responses;
}
Under these conditions, I am wondering if I should use a try-catch mechanism or should I return response in the loop and finally return null. What would you suggest for this situations?
public CommandResponse operation(final UUID uuid) {
final Site site = siteRepository.findByUuid(uuid)
.orElseThrow(() -> new EntityNotFoundException(SITE_ENTITY_NAME));
// code omitted for brevity
for (Type providerType : providerTypeList) {
// operations
return demoService.demoMethod();
}
return null;
}
Well, following the best practices the method demoMethod() should not throw exception, instead capture the exception and send it as response.
This implies either CommandResponse can hold exception response. Following this the code looks as follows:
class CommandResponse<T>{
public T errorResponse();
public T successResponse();
public boolean isSucces();
}
And then later while rendering response you can handle failures/exceptions as per use case.
OR
another way to handle this is having an interface Response with two implementations one for Success & another for failure. Thus making method process to return List<Response>.
It all depends on the requirements, the contract between your process() method and its callers.
I can imagine two different styles of contract:
All Or Nothing: the caller needs the complete responses list, and can't sensibly proceed if some partial response is missing. I'd recommend to throw an exception in case of an error. Typically, this is the straightforward approach, and applies to many real-world situations (and the reason why the concept of exceptions was introduced).
Partial Results: the caller wants to get as much of the complete results list as currently possible (plus the information which parts are missing?). Return a data structure consisting of partial results plus error descriptions. This places an additional burden on the caller (extracting reults from a structure instead of directly getting them, having to explicitly deal with error messages etc.), so I'd only go that way if there is a convincing use case.
Both contracts can be valid. Only you know which one matches your situation. So, choose the right one, and document the decision.

Categories