I have an issue with an Aspect I coded:
@Aspect
@Component
public class MyAudit {
@Pointcut("@annotation(requestMapping)")
public void controller(RequestMapping requestMapping) {
}
@Around("controller(requestMapping)")
public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
...
In one path of the code, I am doing a lookup for authorization and I need to return info to the user WITHOUT executing the method. Basically, I need to shortcut out of the flow.
I have code like this:
log.warn("Not permitted per policy. Returning without executing: " + authError);
Map<String,String> responseBody = new HashMap<>();
responseBody.put("path",request.getContextPath());
responseBody.put("message",authError);
return new ResponseEntity<>(responseBody,HttpStatus.OK);
The problem is that when I return ResponseEntity, it falls right back into my 'around' method. Not sure why it's executing again.
Someone on another thread mentioned that I shouldn't be annotating this as @Component, but I tried removing that and when I do, the @Around method doesn't execute at all.
Can anyone point out what I'm doing wrong?
UPDATE:
Here's the complete class with some code related to business-specific items removed.
import com.ge.aviation.paasport.model.Audit;
import com.ge.aviation.paasport.repository.AuditRepository;
import com.ge.aviation.paasport.util.SecurityUtils;
import static com.google.common.base.Strings.isNullOrEmpty;
import java.lang.annotation.Annotation;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import org.apache.http.HttpResponse;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Aspect
@Component
public class MyAudit {
@Pointcut("@annotation(requestMapping)")
public void controller(RequestMapping requestMapping) {
}
@Around("controller(requestMapping)")
public Object around(ProceedingJoinPoint pjp, RequestMapping requestMapping) throws Throwable {
String authError = null;
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String decision = SecurityUtils.evaluatePolicy(request);
if(!(decision.toUpperCase().equals(SecurityUtils.PERMIT))) {
authError = decision + " : Request not permittted per policy.";
log.warn("Not permitted per policy. Returning without executing: " + authError);
Map<String,String> responseBody = new HashMap<>();
responseBody.put("path",request.getContextPath());
responseBody.put("message",authError);
return new ResponseEntity<>(responseBody,HttpStatus.OK);
}
return pjp.proceed();
}
}
When it executes return new ResponseEntity<>(responseBody,HttpStatus.OK);
in the @Around
advice, it re-enters the around method a 2nd time.
I set a breakpoint on the actual method that would be executed in the normal flow and it's never hit.
Seems it's this ma.invoke method (return ma.invoke(obj, args);
) which is hit when returning the ResponseEntity and it launches right back into the around method again.
package java.lang.reflect;
...
...
public final class Method extends Executable {
...
...
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
}