Persist objects in db using reactive programming and JPA respository - java

I am using web flux in my project and am trying to do simple CRUD operations using JPA repository. However I' unable to persist the object in the DB. The object is always being persisted with null values instead in the DB. Please help. Thanks in advance.
Here is my pojo:
#Entity
#Table(name="tbl_student")
#Data
public class Student {
#Id
#GeneratedValue(strategy= GenerationType.SEQUENCE,generator = "student_seq")
#SequenceGenerator(name="student_seq",allocationSize = 1)
#Column(name="id",insertable =false,nullable = false,updatable = false)
private Long id;
#Column(name="name")
private String name;
#Column(name="school")
private String school;
}
My Repo:
public interface StudentRepository extends JpaRepository<Student,Long> {
}
My controller:
#RestController
#RequiredArgsConstructor
#Slf4j
public class StudentApiControllerImpl extends StudentApiController {
private final StudentRepository StudentRepository;
private final ModelMapper modelMapper;
public Mono<Void> addStudent(#Valid #RequestBody(required = false) Mono<StudentDetails> studentDetails, ServerWebExchange exchange) {
StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class));
return Mono.empty();
}
public Flux<StudentDetails> getStudent(ServerWebExchange exchange) {
return Flux.fromStream(StudentRepository.findAll().stream().map(v ->
modelMapper.map(v,LoginCredential.class))).subscribeOn(Schedulers.boundedElastic());
}
}

You are breaking the reactive chain, thats why nothing happens.
Reactive programming is a lot different than standard java programming so you can't just do what you have done before and think that it will work the same.
In reactive programming one of the most important things to understand is nothing happens until you subscribe
A reactive chain is build by a producer and a subscriber which means someone produces (your application) and someone subscribes (the calling client/application). A Flux/Mono is a producer and nothing will happen until someone subscribes.
// Nothing happens, this is just a declaration
Mono.just("Foobar");
But when we subscribe:
// This will print FooBar
Mono.just("Foobar").subscribe(s -> System.out.println(s));
So if we look at your code, especially this line
// This is just a declaration, no one is subscribing, so nothing will happen
StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class));
A common misconception is that people will solve this by just subscribing.
// This is in most cases wrong
StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class)).subscribe();
Because the subscriber is the calling client, the one that initiated the call. Doing as such might lead to very bad performance under heavier loads. Instead what you do is that you need to return the Mono out to the client, so that the client can subscribe.
public Mono<Void> addStudent(#Valid #RequestBody(required = false) Mono<StudentDetails> studentDetails, ServerWebExchange exchange) {
return StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class))
.then();
}
I am using Mono#then here to throw away the return value and just return a void value to the calling client.
But as you can see, you need to think about it like callbacks, you need to always return so it will build a chain that gets returned to the calling client, so that the client can subscribe.
I highly suggest you read the reactive documentation so you understand the core concepts before starting out with reactive programming.
Reactive programming getting started
Also, another thing, you can not use JpaRepository in a reactive world because it is using a blocking database driver. Which means basically it is not written to work well with Webflux and will give very poor performance. If you want to use a database connection i suggest you look into using R2DBC by spring here is a tutuorial to get it up and running R2DBC getting started
Update:
i see now that you have placed the entire call on its own scheduler which is good since you are using JPA and that will result in less bad performance. But i do recommend still, if possible, to look into using R2DBC for a fully reactive application.
Also, if you insist on using JPA with a blocking database driver, you need to perform your call in a reactive context, since it will return a concrete value. So for instance:
return Mono.fromCallable(() -> StudentRepository.save(modelMapper.map(studentDetails, StudentDTO.class)))
.then()
Which means we are basically executing our function and immediately placing the returned type into a Mono, and then as the above example using Mono#then to discard the return value and just signal that the execution has completed.

Related

Returning Java Object from Mono

I am trying to get Json String from Mono. I tried to use block() method to get object it worked fine , but when I use map/flatmap ,I don't see following lines of code is executed.And I see account Mono is not empty.
private String getJsonString( Mono<Account> account) {
response.map(it->{
**// call is not coming here**
val json = mapper.writeValueAsString(it)
System.out.println(son)
});
}
am I doing anything wrong here?
If you give a read to the official documentation , you will see that:
Nothing happens until you subscribe
Now to understand, In spring boot webflux based microservice, who is the subscriber?, have a look at this stackoverflow question
Now, if you think, you can have blocking and reactive implementations in the same service, unfortunately, it doesn't work like that. For this you have to understand the event loop model on which reactor works. Thus calling a block method at any point in the flow is of no good and is equivalent to using the old blocking spring-web methods. Because the thread in which the request is being processed gets blocked and waits for the outcome of the I/O operation / network call.
Coming to your question in the comment:
But when i use flatMap in my controller to call handler method it goes service method with Object not mono?serviceRequest-->Mono-->Object how this works?
Let me give you a simple example for this:
Suppose you have an employee application, where you want to fetch details of an employee for a given id.
Now in your controller, you will have an endpoint like this:
#GetMapping("/{tenant}/api/employee/{id}")
public Mono<ResponseEntity> getEmployeeDetails(#PathVariable("id") Long employeeId) {
return employeeService.getDetails(employeeId)
.map(ResponseEntity::ok);
}
Now in your service,
public Mono<EmployeeEntity> getDetails(Long employeeId) {
return employeeRepository.findById(employeeId);
}
And your repository will look like this:
#Repository
public interface EmployeeRepository extends ReactiveCrudRepository<EmployeeEntity, Long> {
}

blocking EntityManager operations

I don't want to perform a blocking operation.
Caused by: java.lang.IllegalStateException: You have attempted to perform a blocking operation on a IO thread. This is not allowed, as blocking the IO thread will cause major performance issues with your application. If you want to perform blocking EntityManager operations make sure you are doing it from a worker thread.
Anyone know how to fix this problem?
I only have simple operations. a single findAll request that returns 10 rows. I put Tansactional NEVER
and I still have the problem.
I'm using panache with a simple entity.
#GET
#Path("/type")
#Produces(MediaType.APPLICATION_JSON)
#Transactional(Transactional.TxType.NEVER)
public Response get() {
return AlertType.listAll();
}
public class AlerteType extends PanacheEntityBase
{
#Column(name="ATY_ACTIVE")
private String active;
#Column(name="ATY_ID")
#Id
private Long oraId;
#Column(name="ATY_TYPE")
private String type;
}
thank
If you want to keep using non-reactive code, you can use #Blocking annotation on the method get(). It will offload the computation on a worker thread (instead of one IO thread).
Quarkus is really picky with IO thread, you cannot block them. And if you have something like a database call (or any remote call), that is blocking. So you cannot do it in an IO thread.
More info:
https://quarkus.io/guides/getting-started-reactive
https://quarkus.io/blog/resteasy-reactive-faq/
"Controller" methods (request / route / path handlers, or whatever you call it) is executed on IO thread and not supposed to do any time consuming tasks such as database querying.
If you're not using reactive database client, try wrap them in side a "Service" class.
#ApplicationScoped
public class AlertService {
private final AlertType alertType;
#Inject
public AlertService(AlertType alertType) {
this.alertType = alertType;
}
public List<Alert> listAll() {
return this.alertType.listAll();
}
}
thank you but I already had the call in a service.
I found a solution with mutiny
#GET
#Path("type")
#Produces(MediaType.APPLICATION_JSON)
public Uni<Response> get() {
return Uni.createFrom().item(alertTypeService.findAll().get())
.onItem().transform(data -> Response.ok(data))
.onFailure().recoverWithItem(err -> Response.status(600, err.getMessage()))
.onItem().transform(ResponseBuilder::build)
.emitOn(Infrastructure.getDefaultExecutor())
}
Where alertTypeService.findAll() return a supplier
#Transactional(Transactional.TxType.NEVER)
public Supplier<Set<AlerteTypeDTO>> findAll() {
return () -> alerteTypeDAO.streamAll()
.map(AlertTypeDTOMapper::mapToDTO)
.collect(Collectors.toSet());
}
I don't know if this is the right solution
but it works.
This way the service provides a supplier which will be invoked by the correct thread.
At least that's how I understood it.

"sharing" parts of a reactive stream over multiple rest calls

I have this Spring WebFlux controller:
#RestController
public class Controller
{
#PostMapping("/doStuff")
public Mono<Response> doStuff(#RequestBody Mono<Request> request)
{
...
}
}
Now, say I wanted to relate separate requests coming to this controller from different clients to group processing based on some property of the Request object.
Take 1:
#PostMapping("/doStuff")
public Mono<Response> doStuff(#RequestBody Mono<Request> request)
{
return request.flux()
.groupBy(r -> r.someProperty())
.flatMap(gf -> gf.map(r -> doStuff(r)));
}
This will not work, because every call will get its own instance of the stream. The whole flux() call doesn't make sense, there will always ever be one Request object going through the stream even if there's many of those streams fired at the same time as a result of simultaneous calls coming from clients. What I need, I gather, is some part of the stream that is shared between all requests where I could do my grouping, which led me to this slightly over engineered code
Take 2:
private AtomicReference<FluxSink<Request>> sink = new AtomicReference<>();
private Flux<Response> serializingStream;
public Controller()
{
this.serializingStream =
Flux.<Request>create(fluxSink -> sink.set(fluxSink), ERROR)
.groupBy(r -> r.someProperty())
.flatMap(gf -> gf.map(r -> doStuff(r)));
.publish()
.autoConnect();
this.serializingStream.subscribe().dispose(); //dummy subscription to set the sink;
}
#PostMapping("/doStuff")
public Mono<Response> doStuff(#RequestBody Request request)
{
req.setReqId(UUID.randomUUID().toString());
return
serializingStream
.doOnSubscribe(__ -> sink.get().next(req))
.filter(resp -> resp.getReqId().equals(req.getReqId()))
.take(1)
.single();
}
And this kind of works, though it looks like I am doing things I shouldn't (or at least they don't feel right), like leaking the FluxSink and then injecting a value through it while subscribing, adding a request ID so that I can then filter the right response. Also, if error happens in the serializingStream then it breakes everything for everyone, but I guess I could try to isolate the errors to keep things going.
The question is, is there a better way of doing this that doesn't feel like an open heart surgery.
Also, related question for a similar scenario. I was thinking about using Akka Persistence to implement event sourcing and have it trigerred from inside that Reactor stream. I was reading about Akka Streams that allow to wrap an Actor and then there's some ways of converting that into something that can be hooked up with Reactor (aka Publisher or Subscriber), but then if every requests gets it's own stream, I am effectively loosing back pressure and am risking OOME because of flooding the Persistent Actor's mailbox, so I guess that problem falls in to the same category like the one I described above.

Where to use Mono/Flux?

I'm kind of forced to switch to reactive programming (and in a short time frame), using WebFlux and I'm having a really hard time understanding it. Maybe because the lack of examples or because I never did functional programming.
Anyways, my question is where to use Mono/Flux and where can I work with normal objects? E.g. my controller is waiting for a #Valid User object, should that be #Valid Mono or something like Mono<#Valid User>? If let's say it was just a User object, I pass it to my service layer, and I want to encode the password before saving it to the reactive MongoDb, should I write:
User.setPassword(...);
return reactiveMongoDbRepository.save(user); //returns Mono<User> which is returned by the Controller to the View
Or it should be something like
return Mono.just(user).map.flatmap(setPasswordSomewhereInThisHardToFollowChain).then.whatever.doOnSuccess(reactiveMongoDbRepository::save);
In other words, am I forced to use this pipeline thing EVERYWHERE to maintain reactiveness or doing some steps the imperative way, like unwrapping the object, working on it, and wrapping it back is OK?
I know my question seems to be silly but I don't have the big picture at all, reading books about it didn't really help yet, please be gentle on me. :)
Use pipelining when you require sequential, asynchronous and lazy execution. In all other cases (when you are using a non-blocking code) you're free to choose any approach and it's generally better to use the simplest one.
Sequential non-blocking code can be organised in functions that you can integrate with reactive pipeline using map/filter/doOnNext/... components.
For example, consider the following Order price calculation code.
class PriceCalculator {
private final Map<ProductCode, Price> prices;
PriceCalculator(Map<ProductCode, Price> prices) {
this.prices = prices;
}
PricedOrder calculatePrice(Order order) { // doesn't deal with Mono/Flux stuff
Double price = order.orderLines.stream()
.map(orderLine -> prices.get(orderLine.productCode))
.map(Price::doubleValue)
.sum();
return new PricedOrder(order, price);
}
}
class PricingController {
public Mono<PricedOrder> getPricedOrder(ServerRequest request) {
OrderId orderId = new OrderId(request.pathVariable("orderId"));
Mono<Order> order = orderRepository.get(orderId);
return order.map(priceCalculator::calculatePrice)
}
}

Asynchronous processing with fallback java

I am working on an java application that will makes calls to a web service, I dont want to incur additional latency while making these calls hence I am planning on doing this asynchronously. Using threads is one way to go about it but this approach might become unreliable if the calls to the dependent service fail because of various reasons. So essentially what I am looking is some kind of in-process asynchronous service will fallback to temporarily store (inprocess database ?) and retry the failed requests. Are there are any exiting solutions out there that achieve this ? If not it would help if someone could point me to something that does a similar task like this.
Thanks
Actually, I've not yet tried it, but Reactor is something like Node.js and should allow you to program using event-driven paradigm.
Please check it out and let us know if it suits your needs.
Quarkus has easy built in reactive asynchronous call processing.
Like:
#ApplicationScoped
#RegisterForReflection
#Path("/")
public class JokesServiceCallManager {
private static final Logger LOGGER =
LoggerFactory.getLogger(JokesServiceCallManager.class);
#Inject
JokeResponseHandler jokeResponseHandler;
#Inject
JokeSetupAdapter jokesSetupAdapter;
#Inject
JokeReactionAdapter jokesReactionAdapter;
public Uni<Response> getData(String id,String correlationId) {
LOGGER.debug("********** getData(String id) id = " + id);
Uni<Response> uniSetup = jokesSetupAdapter.getByIdAsync(id);
Uni<Response> uniReaction =
jokesReactionAdapter.getByIdAsync(id);
return Uni.combine().all().unis(uniSetup, uniReaction )
.asTuple().onItem().transformToUni(tuple ->
jokeResponseHandler.createUniResponse(tuple.getItem1(),
tuple.getItem2()));
// .onFailure().invoke(exception ->
jokeResponseHandler.buildUniExceptionResponse(exception));
}
Which returns a tuple of all the calls when complete.
Simply allowing the service return to be cast to an Uni makes it all reactive (non-blocking)
The calls are as simple as :
import javax.ws.rs.core.Response;
import
org.eclipse.microprofile.rest.client.annotation.RegisterClientHeaders;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
import io.smallrye.mutiny.Uni;
#RegisterRestClient(configKey="setup-api")
#RegisterClientHeaders(SetupHeaderFactory.class)
public interface JokesSetupService {
#GET
#Path("/jokesetup/{id}")
#Produces(MediaType.APPLICATION_JSON)
Uni<Response> getByIdAsync(#PathParam("id") String id);
}

Categories

Resources