Mono response from a method which returns void - spring-boot

I have a service method which does not result anything, but can return an HttpException.
example
class Service{
public void myService() throws HttpException{
//do something
}
}
My calling class has a method which is supposed to return a Mono. This method calls myService().
class Caller{
#Autowire
Service service;
public Mono<Response> callMyService(){
return Mono.just("abc")
.doOnSuccess(service.myService())
.thenReturn(new Response()); //this should return Mono<Response>
}
}
My question, is how can I write callMyService() in a good way? Mono.just("abc") doesn't seem right implementation.

You should use Mono<Void> for this purpose. This mono will not forward any data, it will only signal error or completion.
You can create it using then()
Also, remember that doOnSuccess() is side effect. You should not use it for data processing, maybe use map() or flatMap(). For you case, maybe you can use Mono.fromCallable(()->service.myService()), but that may not be correct depending on what service actually does.

Related

Obtaining the result of a Mono in order to pass it onto a JpaRepository or another non reactive class

I would like to know what is the appropriate way obtaining an object from a Mono (or Flux) to pass onto a non-reactive method such as a JpaRepository.
Here is the way I did it:
#Service
public class ReactiveAccountService {
//AccountService's methods take non-mono/non-flux objects as arguments
private AccountService accountService;
public ReactiveAccountService(AccountService accountService) {
this.accountService = accountService;
}
public Mono<Void> signUp(Mono<Account> accountMono) {
//Account is a Jpa entity
accountMono.subscribe(account -> accountService.signUp(account));
return Mono.empty();
}
}
How can this be improved? Can someone please advise?
The better way to do that is like this:
public Mono<Void> signUp(Mono<Account> accountMono) {
//Account is a Jpa entity
return accountMono.flatMap(account -> {
accountService.signUp(account);
return Mono.empty();
});
}
This way you follow Reactive Streams requirements and don't bother the execution flow with your blocking code. Plus according the Spring WebFlux requirements you don't subscribe in your own code, but deffer everything to the container which is an initiator of that Mono<Account>. The actual execution will happen, when there is enough resources in the Web (Reactive) container to subscribe to the returned Mono.

Spring AOP does not run as expected [duplicate]

I have several Aspects coded in my application. All others works except for the following.
Service Interface
package com.enbiso.proj.estudo.system.service;
...
public interface MessageService {
...
Message reply(Message message);
Message send(Message message);
...
}
Service Implementation
package com.enbiso.proj.estudo.system.service.impl;
....
#Service("messageService")
public class MessageServiceImpl implements MessageService {
...
#Override
public Message reply(Message message) {
...
return this.send(message);
}
#Override
public Message send(Message message) {
...
}
}
Aspect
#Aspect
#Component
public class NewMessageAspect {
...
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..))",
returning = "message")
public void perform(Message message){
...
}
}
When I try to execute the send method the debug point is not getting hit in the aspect perform.
UPDATE
I did some investigations and found that this doesn't work, when the send method is invoked from the reply method as below
#Autowire MessageService messageService;
...
messageService.reply(message);
But if I call the method messageService.send(message) it works fine. But as reply method is calling send method internally, shouldn't it also invoke the aspect?
I have no idea what i have done wrong. Please help me.
Thank you jst for clearing the things up. Just for the information purposes for the future developer in SO, I'm posting the full answer to this question
Lets assume that there is a bean from SimplePojo
public class SimplePojo implements Pojo {
public void foo() {
this.bar();
}
public void bar() {
...
}
}
When we call the method foo(), it reinvokes the method bar() inside it. Even thought the method foo() is invoked from the AOP Proxy, the internal invocation of the bar() is not covered by the AOP Proxy.
So eventually this makes, if there are any advices attached to the method bar() to not get invoked
Solution
Use AopContext.currentProxy() to call the method. Unfortunately this couples the logic with AOP.
public void foo() {
((Pojo) AopContext.currentProxy()).bar();
}
Reference:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
You are running into a limitation of Spring AOP on self-invocation. You basically can get around it by using AopContext.currentProxy(), refactor code into different beans, or use full ApsectJ weaving.
See explanation here and workaround(s).
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
I guess the problem is the #args condition.
Spring documentation states the following:
#args - limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given type(s)
Therefore the parameter of #args has to be a type expression. So the correct pointcut expression is
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(..)) && args(com.enbiso.proj.estudo.system.service.impl.Message")
or simply
#AfterReturning(value = "execution(* com.enbiso.proj.estudo.system.service.impl.MessageServiceImpl.send(com.enbiso.proj.estudo.system.service.impl.Message))")
Please adjust the package of Message if it doesn't fit.

Using #SubscribeMapping annotated method for RPC-like behavior when return value is deferred

I really like #SubscribeMapping approach to implement RPC-like semantic with STOMP-over-Websocket.
Unfortunately its "magic" requires that annotated method returns a value. But what if return value is not readily available? I want to avoid blocking inside the method waiting for it. Instead I'd like to pass a callback that will publish a value when it's ready. I thought I could use messaging template's convertAndSendToUser() inside a callback to do that. Turns out #SubscribeMapping handling is quite special and is not possible with instance of SimpMessageSendingOperations.
I was able to achieve my goal by calling handleReturnValue() on a SubscriptionMethodReturnValueHandler, but the overall mechanics of this is very tedious if not hackish (like providing dummy instance of MethodParameter to handleReturnValue()):
public class MessageController {
private final SubscriptionMethodReturnValueHandler subscriptionMethodReturnValueHandler;
#Autowired
public MessageController(SimpAnnotationMethodMessageHandler annotationMethodMessageHandler) {
SubscriptionMethodReturnValueHandler subscriptionMethodReturnValueHandler = null;
for (HandlerMethodReturnValueHandler returnValueHandler : annotationMethodMessageHandler.getReturnValueHandlers()) {
if (returnValueHandler instanceof SubscriptionMethodReturnValueHandler) {
subscriptionMethodReturnValueHandler = (SubscriptionMethodReturnValueHandler) returnValueHandler;
break;
}
}
this.subscriptionMethodReturnValueHandler = subscriptionMethodReturnValueHandler;
}
#SubscribeMapping("/greeting/{name}")
public void greet(#DestinationVariable String name, Message<?> message) throws Exception {
subscriptionMethodReturnValueHandler.handleReturnValue("Hello " + name, new MethodParameter(Object.class.getMethods()[0], -1), message);
}
}
So my question is simple: Is there a better way?

Spring Controller - forking request, return value before long run function ends

I have controller and long run function in it, like:
#Controller
#RequestMapping("/deposit")
public class DepositController {
#RequestMapping
public ModelAndView getNewJob(long userId, Model model) {
//execute function that can runs a lot of time ...
longRunFunction();
return new ModelAndView("jobTasks");
}
public void longRunFunction(){
// process long run function
}
}
My question is :
How can I execute the longRunFunction()
and return ModelAndView("jobTasks") answer to the browser without waiting for the end of the function?
Thank you !
Hi, I found nice example here http://krams915.blogspot.co.il/2011/01/spring-3-task-scheduling-via.html
This can be done using Asynch support in Spring Framework, essentially delegate the long running task to another service, the method of which is annotated with #Async annotation, this task would then be executed by a threadpool and control will return back to your caller immediately.
Here is much more detailed reference: http://docs.spring.io/spring-framework/docs/3.2.3.RELEASE/spring-framework-reference/html/scheduling.html#scheduling-annotation-support-async
public class SampleBeanImpl implements SampleBean {
#Async
void longRunFunction() { … }
}
Add #Async to the method declaration of longRunningMethod. But to make this work without AspectJ weaving you need to put this method in an other bean.

AOP for Spring Controllers

Spring's AOP functionality is pretty great, and it makes it easy to add cool and useful annotations to controllers. For example, I wrote an #Authenticated annotation that either allows authenticated users through to the controller method or redirects to the login page. Fun stuff.
However, Spring's controllers can return all sorts of different types. They can return Strings, ModelAndView objects, or even void. There are methods in my code base that use all three types. However, I'd like to change my #Authenticated annotation to render and return a particular page, which I was hoping to do by returning a ModelAndView object. Is the only way to accomplish this by requiring all of my controller methods to return a ModelAndView?
Example of a controller I'd like to have:
#Controller
public class MyController() {
#Authenticated
#RequestMapping("/myscore")
public String myScorePage(ModelMap model) {
return "myScorePage";
}
#Authenticated
#RequestMapping("/anotherPage")
public ModelAndView something() {
return new ModelAndView("anotherPage",someModelStuff());
}
}
#Aspect
public class NotVeryUsefulAspect {
#Around("#annotation(Authenticate)")
public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
if( isAuthenticated() ) {
return pjp.proceed();
} else {
return /* Oh no what goes here, I want to render a FAILURE page without redirecting */
}
}
}
Ha, figured it out!
I decided to use the ProceedingJoinPoint passed to the aspect method to figure out the return type of the original method. Then I made a set of possible "failure" results for the aspect method based on what type of return is passed. For example, if the method originally returned a String, I return "failure_page", and if the method returned a ModelAndView, I return a new ModelAndView("failure_page").
Works quite well! Unfortunately, I may not have an opportunity to set a model object if it returns a string and doesn't take a ModelMap as a parameter, but I can deal with that for an error page just fine.
Yes it seams that you are right.
You need to change your methods so that all return an ModelAndView.
Or you need two Aspects, one for return type ModelAndView and one for String - and then all your controller methods must match
But Authorization is already build in in Spring Security and you do not need to implement it by your own.

Resources