Spring Aspect - How to identify which Pointcut triggers the function - spring-boot

I want to log Controller and the rest of packages differently. I know I can use 2 separate methods for this but these 2 methods are very similar, so I want to add a code to check that would look something like this
#Around("controllerPoint() || theRest()")
public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
if( called from controllerPoint() ) {
execute this short section of code # (1)
}
// rest of code
What would this code be like?
Also, if after I execute (1) and I want to pass a variable to this same method again when it executes for other packages, how can I do it?

you can invoke the method like the below which will return your method name
joinPoint.getSignature().getName()

You could get method name, from join point:
#Aspect
#Configuration
public class TrackingConfig {
#Around("execution(* your.package.Controller.*(..))")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
String methodName = pjp.getSignature().getName();
if ("theRest".equals(methodName)) {
System.out.println("AROUND! theRest ");
} else if ("controllerPoint".equals(methodName)) {
System.out.println("AROUND! controllerPoint ");
}
return pjp.proceed();
}
}

Related

thenThrow() not throwing an exception

I have a method in OneServiceImpl class as follows. In that class I am calling an interface method from another class.
public class OneServiceImpl {
//created dependency
final private SecondService secondService;
public void sendMessage(){
secondService.validateAndSend(5)
}
}
public interface SecondService() {
public Status validateAndSend(int length);
}
public class SecondServiceImpl {
#Override
public Status ValidateAndSend(int length) {
if(length < 5) {
  throw new BadRequestException("error", "error");
}
}
}
Now when I am try to perform unit test on OneServiceImpl I am not able to throw a BadRequestException.
when(secondService.validateAndSend(6)).thenThrow(BadRequestException.class);
Not quite sure what your use case is, but I think you should write an own test to accept and test an exception.
#Test(expected = BadRequestException.class)
public void testValidateAndSend(){
SecondService secondService = new SecondService();
secondservice.ValidateAndSend(6); //method should be lowercase
}
Not sure this is the case considering you didn't post a full example of code + unit tests, but your mock will throw only when you are passing 6 as parameter. When configuring the behaviour of your mock with when you are telling it to throw only when the validateAndSend method is called with parameter 6.
when(secondService.validateAndSend(6)).thenThrow(...)
In your code you have 5 hardcoded. So that mock will never throw for the code you have, because it's configured to react to an invocation with parameter 6 but the actual code is always invoking it passing 5.
public void sendMessage(){
secondService.validateAndSend(5)
}
If the value passed to the mock is not important you could do something like the following, that will throw no matter what's passed to it:
when(secondService.validateAndSend(any())).thenThrow(BadRequestException.class);
On the other hand, if the value is important and it has to be 5 you could change the configuration of your mock with:
when(secondService.validateAndSend(5)).thenThrow(BadRequestException.class)

Returning proper value from #AfterThrowing

I am new to String, SpringBoot.
Can we suppress thrown exception in a method annotated with #AfterThrowing?
I mean when an exception is thrown, it will suppress that and will return a default value on behalf of the invoking method?
Say, I have a controller -
#RestController
public class MyRestController implements IRestController{
#Override
#GetMapping("hello-throw")
public String mustThrowException(#RequestParam(value = "name")final String name) throws RuntimeException {
System.out.println("---> mustThrowException");
if("Bakasur".equals(name)) {
throw new RuntimeException("You are not welcome here!");
}
return name + " : Welcome to the club!!!";
}
}
I have created a #AspectJ, as follows -
#Aspect
#Component
public class MyAspect {
#Pointcut("execution(* com.crsardar.handson.java.springboot.controller.IRestController.*(..))")
public void executionPointcut(){
}
#AfterThrowing(pointcut="executionPointcut()",
throwing="th")
public String afterThrowing(JoinPoint joinPoint, Throwable th){
System.out.println("\n\n\tMyAspect : afterThrowing \n\n");
return "Exception handeled on behalf of you!";
}
}
If I run this & hit a ULR like - http://localhost:8080/hello-throw?name=Bakasur
I will get RuntimeException, but, I want to return a default message like - Exception handeled on behalf of you!, can we do it using #AfterThrowing?
I know it can be done using #Around, but around will be called on every hit of the url, that I do not want
What you want to do is Exception Handling on the controller. You don't need to build it yourself, Spring already supports you with some annotations like #ExceptionHandler and #ControllerAdvice. Best would be to follow this example: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc#using-controlleradvice-classes
#ControllerAdvice
class GlobalControllerExceptionHandler {
#ResponseStatus(HttpStatus.CONFLICT) // 409
#ExceptionHandler(DataIntegrityViolationException.class)
public void handleConflict() {
// Nothing to do
}
}
#ControllerAdvice
class GlobalDefaultExceptionHandler {
public static final String DEFAULT_ERROR_VIEW = "error";
#ExceptionHandler(value = Exception.class)
public ModelAndView
defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
// If the exception is annotated with #ResponseStatus rethrow it and let
// the framework handle it - like the OrderNotFoundException example
// at the start of this post.
// AnnotationUtils is a Spring Framework utility class.
if (AnnotationUtils.findAnnotation
(e.getClass(), ResponseStatus.class) != null)
throw e;
// Otherwise setup and send the user to a default error-view.
ModelAndView mav = new ModelAndView();
mav.addObject("exception", e);
mav.addObject("url", req.getRequestURL());
mav.setViewName(DEFAULT_ERROR_VIEW);
return mav;
}
}
You should use the fully qualified name of the class before method's name when you're referring to a pointcut. So, you should change #AfterThrowing something like this.
#AfterThrowing(pointcut="packageName.MyAspect.executionPointcut()",
throwing="th")
Please note that packageName is full package name of MyAspect.

Conditional execution of a method using Aspects in Spring AOP

I am new to Spring AOP. I need to execute methods only if the user is authorized.
Here's my code.
#Before("some pointcut")
public HttpStatus checkUserAuthentication(String userName)
{
if( userAuthorized(userName) )
{
//go on executing method
} else {
return HttpStatus.FORBIDDEN;
}
}
Is there any alternative for ProceedingJoinPoint.proceed when using JoinPoint or can I use ProceedingJoinPoint with #Before advice? How to proceed with executing the if statement if the user is authorized.
I solved this using #Around advice. and changing the return type to Object so that it can return ProceedingJoinPoint on successfull verification.
#Around("some pointcut")
public Object checkUserAuthentication(ProceedingJoinPoint pjp, String userName)
{
if( userAuthorized(userName) )
{
return pjp.roceed();
} else {
return new ResponseEntity<>(HttpStatus.FORBIDDEN);
}
}
using #Around as advice the control can be passed to the method after verification.

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.

Avoid nested calls

Let's say I have an aspect wrapper on all public methods of my services which detaches entities from database before returning them to controller:
#Around("execution(public * *(..)) && #within(org.springframework.stereotype.Service)")
When one service is calling another directly, this wrapper is being triggered as well. For instance:
#Service
class ServiceA {
#Autowired
ServiceB b;
public void foo() {
b.bar();
}
}
#Service
class ServiceB {
public void bar() {
}
}
When I call ServiceA.foo(), the wrapper is triggering around the nested call to bar() as well.
It should trigger around the call to foo(), but not bar(). How can I avoid this?
I've sometimes resolved this kind of problems using ThreadLocal variables. Try something like:
#Aspect
public class DetacherAspect {
private final ThreadLocal<Object> threadLocal = new ThreadLocal<Object>();
#Around("execution(public * *(..)) && #within(org.springframework.stereotype.Service)")
public Object execute(ProceedingJoinPoint pjp) throws Throwable {
boolean isNested = threadLocal.get() != null;
if (!isNested) {
// Set some object (better create your own class) if this is the first service
threadLocal.set(new Object());
}
try {
... // Your aspect
} finally {
// Clean thread local variables
if (!isNested) {
threadLocal.remove();
}
}
}
}
Obviously, this will only work when all calls are done in the same thread. Thread local variables have some other drawbacks too and is good to read about them.
I am on the road with my iPad only, so I cannot test it now, but you could try something along the lines of:
pointcut myCalls() :
execution(public * *(..)) && #within(org.springframework.stereotype.Service);
pointcut myCallsNonRecursive() :
myCalls() && !cflowbelow(myCalls())
around() : myCallsNonRecursive() {
// ...
}
Sorry for the AspectJ native syntax, I am just more familiar with it.

Resources