Throw new RuntimeException() from a Mono, in AOP - spring

I have a reactive springboot application, in it an aspect
#Before("approveRejectPointcut()")
public void logAfterReturning(JoinPoint joinPoint) {
Status newStatus = AspectUtils.returnFirstParameterOfTypeOrFail(allParameters, Status.class, "approveRejectPointcut");
String comments = AspectUtils.returnFirstParameterOfTypeOrFail(allParameters, String.class, "approveRejectPointcut");
Mono<Object> someObjectOrException = someService.updateApplicationStatus(appId, newStatus, comments);
someObjectOrException
.subscribe(i->log.info(i),
error->{
log.info("we have some ex: "+error.getMessage());
throw new RuntimeException("PLEASE LORD: "+error.getMessage());
});
}
What happens here, the updateApplicationStatus() from some service throws at some point a Business exception(which is good), in this aspect I print the exception message, which is also good. However, when i try to throw a business exception (a RuntimeException at it's base) .. i can see this exception in the console, however.. it does not reach the client.
I suspect it is being thrown on a different thread. Any clues ?

In the end, changed the aspect to #Around
#Around("approveRejectPointcut()")
public Mono<Object> logAfterReturning(ProceedingJoinPoint pjp) {
...
Mono<Object> someObjectOrException = someService.updateApplicationStatus(appId, newStatus, comments);
someObjectOrException
.map(unused->pjp.proceed(pjp.getArgs())
.onErrorMap(RuntimeException.class, (s)->{
return new GenericBusinessException(s.getMessage());
});
}
this way in case all goes well in the service -> we carry on with the execution, otherwise, we throw our business exception with the exception message from the service. Perhaps that map() should be replaced with some other operator accepting a funtion.. :)

Related

Spring Boot Exception(Error) Handling for RESTful Services

I have the following RESTful Services method :
#PostMapping("/ajouterNewField")
public String ajouterField(#Valid #ModelAttribute("field") Fields field, Model model) throws IOException {
fieldDao.save(field);
// SOME CODE
return displayListeChamps( model);
}
The method is working fine and my question is how to handle any error (database not connected ...) or every issue that can happen durring the execution of this RESTful Services method.
You can use #ControllerAdvice
Refer to the code below
#ControllerAdvice
public String NyExceptionHandlerAdvice {
private final Logger logger = ...;
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler({MyRunTimeException.class})
public void handleMyRunTimeException(Exception e) {
logger.error("Exception : ", e);
}
return MY_ERROR_STRING;
}
Best Practice is:
You can have your code throw RunTimeExceptions and handle all of them together or separately in handler methods similar to handleMyRunTimeException above.
You can decide what status code your request should return upon exception.
Basically you'll have to a sort of exception handler for any kind of exception your method might throw:
public class FooController{
// ...
#ExceptionHandler({ CustomException1.class, CustomException2.class })
public void handleException() {
//
}
}
Here's a nice article about that: https://www.baeldung.com/exception-handling-for-rest-with-spring

#Around Aspect in Spring AOP throwing Null Pointer Exception

Can someone help me out figuring why my #Around advice throws a Null Pointer Exception here. I have made sure that my advice returns an Object same as the method to proceed, yet I am getting the exception.
#Aspect
public class BasicAuthAspect
{
#Around("execution(* *..impl.PreferenceImpl.*(..))")
public Object auth(ProceedingJoinPoint joinPoint) {
log.debug("Inside Basic Auth check method..");
ServletRequestAttributes requestAttributes=null;
requestAttributes=(ServletRequestAttributes)
RequestContextHolder.getRequestAttributes();
if(requestAttributes!=null){
request =requestAttributes.getRequest();
Object[] signatureArgs = joinPoint.getArgs();
try {
return (Response) joinPoint.proceed(signatureArgs);
} catch (Throwable e) {
return Response.status(HttpStatus.SC_UNAUTHORIZED).build();
}
}
}
else{
return Response.status(HttpStatus.SC_UNAUTHORIZED).build();
}
}
}
Here is my method to proceed(PreferenceImpl.java):
#Override
public Response postPreferences( String preference) {
String responseReturned=searchDAO.postPreference( XSSUtils.normalize(preference));
if(responseReturned!=null)
response=Response.status("success").build();
else
response=Response.status("failure").build();
return response;
}
Here goes the error log:
java.lang.NullPointerException
at java.lang.String.<init>(String.java:556)[:1.7.0_80]
at org.apache.cxf.transport.http.AbstractHTTPDestination.getAuthorizationPolicyFromMessage(AbstractHTTPDestination.java:163)[173:org.apache.cxf.cxf-rt-transports-http:2.7.3]
at org.apache.cxf.transport.http.AbstractHTTPDestination.setupMessage(AbstractHTTPDestination.java:349)[173:org.apache.cxf.cxf-rt-transports-http:2.7.3]
at org.apache.cxf.transport.http.AbstractHTTPDestination.setupMessage(AbstractHTTPDestination.java:258)[173:org.apache.cxf.cxf-rt-transports-http:2.7.3]
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.serviceRequest(JettyHTTPDestination.java:345)[179:org.apache.cxf.cxf-rt-transports-http-jetty:2.7.3]
at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:319)[179:org.apache.cxf.cxf-rt-transports-http-jetty:2.7.3]
at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:72)[179:org.apache.cxf.cxf-rt-transports-http-jetty:2.7.3]
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1040)[79:org.eclipse.jetty.server:7.6.8.v20121106]
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:976)[79:org.eclipse.jetty.server:7.6.8.v20121106]
You could have several problems here:
Your pointcut intercepts all PreferenceImpl methods, but it seems you only want to catch a single one. I suggest you make the pointcut more specific.
You are assuming return type Response in the advice method, but your pointcut assumes * and the advice method itself returns Object, so theoretically another method could return another type and the cast would fail (see first problem).
You are trying to provide arguments to proceed(), but that is actually not necessary. So just remove the getArgs() stuff, you do not need it.
If despite my hints you still have problems, let me know and I can provide some sample code. BTW, maybe you want to read a basic Spring AOP tutorial. :-)

Spring Boot Exception details

I am trying to log the exception in the spring boot based web service.
So I have used GlobalExceptionHandler
My code :
#ControllerAdvice
#RestController
public class GlobalExceptionHandler {
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = Exception.class)
public String handleException(Exception e){
System.out.println("Ankit == "+e.getMessage());
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
System.out.println(errors.toString());
return e.getMessage();
}
}
the code is working fine. What I want is exception details. I mean the code where the exception occurs? File name / line ? or do I have to parse the stacktrace? I mean spring boot must have thought something for this?
Using IDE
If you are using any IDE then go to Console Window.
Clear console
Repeat action that causes Exception
Search in Console (CTRL + F) for ERROR
Look for line above(Look for 2-3 lines if you don't find immediate above) the line which contains ERROR. This line has details of Class, Method where Exception has occurred.
Without looking at Console or Logs
If you want to use it in production then, handling atleast known exceptions(like BAD_REQUEST, NOT_FOUND etc.) the way it is done below might be helpful (adding an extra parameter to Exception Class) :
Employee employee = employeeService.getEmployeeById(employeeId);
if (null == employee) {
logger.error("No tenant exists for employeeId:"+employeeId);
throw new ObjectNotFoundException("Emplyee Not Found", this.getClass().getSimpleName();));
}
here this.getClass().getSimpleName(); will be passed as parameter from EmployeeController class. So in ObjectNotFoundException we can add a parameter ClassName and When you handle it in GlobalExceptionHandler, you can do it as it is done below,
#ControllerAdvice
#RestController
public class GlobalExceptionHandler {
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(value = Exception.class)
public String handleException(Exception e){
System.out.println("Ankit == "+e.getMessage());
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
String classWithExceptionName = e.getClassName();
// you need to add this above getter method to your Exception Class
System.out.println(errors.toString());
return e.getMessage();
}
}
This is for known common exceptions. We need to add extra parameter(ClassName) to All Custom Exceptions that you are throwing and that might be little extra code but i think that is the way. Hope it helps now.

Get failure exception in #HystrixCommand fallback method

Is there a way to get the reason a HystrixCommand failed when using the #HystrixCommand annotation within a Spring Boot application? It looks like if you implement your own HystrixCommand, you have access to the getFailedExecutionException but how can you get access to this when using the annotation? I would like to be able to do different things in the fallback method based on the type of exception that occurred. Is this possible?
I saw a note about HystrixRequestContext.initializeContext() but the HystrixRequestContext doesn't give you access to anything, is there a different way to use that context to get access to the exceptions?
Simply add a Throwable parameter to the fallback method and it will receive the exception which the original command produced.
From https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-javanica
#HystrixCommand(fallbackMethod = "fallback1")
User getUserById(String id) {
throw new RuntimeException("getUserById command failed");
}
#HystrixCommand(fallbackMethod = "fallback2")
User fallback1(String id, Throwable e) {
assert "getUserById command failed".equals(e.getMessage());
throw new RuntimeException("fallback1 failed");
}
I haven't found a way to get the exception with Annotations either, but creating my own Command worked for me like so:
public static class DemoCommand extends HystrixCommand<String> {
protected DemoCommand() {
super(HystrixCommandGroupKey.Factory.asKey("Demo"));
}
#Override
protected String run() throws Exception {
throw new RuntimeException("failed!");
}
#Override
protected String getFallback() {
System.out.println("Events (so far) in Fallback: " + getExecutionEvents());
return getFailedExecutionException().getMessage();
}
}
Hopefully this helps someone else as well.
As said in the documentation Hystrix-documentation getFallback() method will be thrown when:
Whenever a command execution fails: when an exception is thrown by construct() or run()
When the command is short-circuited because the circuit is open
When the command’s thread pool and queue or semaphore are at capacity
When the command has exceeded its timeout length.
So you can easily get what raised your fallback method called by assigning the the execution exception to a Throwable object.
Assuming your HystrixCommand returns a String
public class ExampleTask extends HystrixCommand<String> {
//Your class body
}
do as follows:
#Override
protected ErrorCodes getFallback() {
Throwable t = getExecutionException();
if (circuitBreaker.isOpen()) {
// Log or something
} else if (t instanceof RejectedExecutionException) {
// Log and get the threadpool name, could be useful
} else {
// Maybe something else happened
}
return "A default String"; // Avoid using any HTTP request or ypu will need to wrap it also in HystrixCommand
}
More info here
I couldn't find a way to obtain the exception with the annotations, but i found HystrixPlugins , with that you can register a HystrixCommandExecutionHook and you can get the exact exception in that like this :
HystrixPlugins.getInstance().registerCommandExecutionHook(new HystrixCommandExecutionHook() {
#Override
public <T> void onFallbackStart(final HystrixInvokable<T> commandInstance) {
}
});
The command instance is a GenericCommand.
Most of the time just using getFailedExecutionException().getMessage() gave me null values.
Exception errorFromThrowable = getExceptionFromThrowable(getExecutionException());
String errMessage = (errorFromThrowable != null) ? errorFromThrowable.getMessage()
this gives me better results all the time.

Spring #Async with Future and Callable

I am trying to implement a generic class that executes a callable asynchronously, but I am not sure about the semantics.
#Component
public class MyCallerImpl implements MyCaller {
#Async
#Override
public <T> Future<T> runAsync(Callable<T> callable) throws Exception {
return new AsyncResult<T>(callable.call());
}
}
Basically, this component executes arbitrary actions from any callable asynchronously using the #Async annotation.
I am unsure about the Exception in the throws clause of the method signature.
A Junit test:
#ContextConfiguration("classpath:test-config.xml")
#RunWith(SpringJUnit4ClassRunner.class)
public class RunnerTest{
#Resource(name="myCallerImpl")
private MyCaller myCaller;
#Test
public void testException(){
final Callable<String> callable = new Callable<String>(){
#Override
public String call() throws Exception{
throw new MyException("foobar");
}
};
try
{
final Future<String> future = myCaller.runAsync(callable); // this can throw Exception due to Callable.call()
future.get(); // this can throw InterruptedException and ExecutionException
}
catch (final InterruptedException ie)
{
// do someting
}
catch (final ExecutionException ee)
{
// we want to check the cause
final Throwable cause = ee.getCause();
assertTrue(cause instanceof MyException);
}
catch (final Exception e)
{
// Not sure what to do here.
// Must be caught as it is declared to
// be thrown from the MyCaller.runAsync() method
// but nothing will really ever get here
// since the method is #Async and any exception will be
// wrapped by an ExecutionException and thrown during Future.get()
fail("this is unexpected);
}
My question is what to do about the Exception declared in the throws clause of MyCallerImpl.runAsync()?
The only reason I have declared it is because of the way I am calling the callable. Originally I had the following in the async method:
FutureTask<T> futureTask = new FutureTask<T>(callable);
futureTask.run();
return futureTask;
But when an exception is thrown from the callable in that instance, it gets wrapped twice in an ExecutionException, the first time when FutureTask.run() is called eventually FutureTask.Sync.innerRun() catches the exception and calls innnerSetException() and a second time when the AsyncExecutionIntercepter gets the result from the Future via Future.get(), which eventually again checks if there is an exception and throws a new ExecutionException wrapping the ExecutionException caught in innerRun()
I also tried to do the following in the method:
FutureTask<T> futureTask = new FutureTask<T>(callable);
return futureTask;
I had figured that since the AsyncExecutionInterceptor calls Future.get(), that the callable would be called immediately, but that was not the case. It just hangs on FutureTask.acquireSharedInterruptibly() and never returns.
Maybe I'm in over my head here. It works how I have it set-up with the callable now, but I rather not have the method signature declare a throws Exception.
Any advice? Should I forget about this generic way of doing async calls with a callable?
There are 2 layers of exception here.
one:
the exception leading to the calling of the Callable
if (string.equals("X")){ callable.call();}
two:
the exception caused when calling the callable.call() method (your "throw new MyException("foobar");")
since you do not have any other code prior to "callable.call();", it would be safe to remove the checked exception.
Change
public <T> Future<T> runAsync(Callable<T> callable) throws Exception
to
public <T> Future<T> runAsync(Callable<T> callable)
additionally, you can code it this way
final Future<String> future = myCaller.runAsync(callable);
try
{
future.get(); // this can throw InterruptedException and ExecutionException
}
catch (final InterruptedException ie)
{
// do someting
}
catch (final ExecutionException ee)
{
// we want to check the cause
final Throwable cause = ee.getCause();
assertTrue(cause instanceof MyException);
}

Resources