I used Spring AOP @Before advice in Spring boot application, and it should execute before hitting any api's. My task/requirement :- If in the request header application-name is not passed then we should modify the header and add to 'unknown' value to the application-name for every API. I am modifying the header in the AOP @before advice using HttpServletWrapper class as shown below.
Problem is - the AOP should return updated HttpServletrequest to a controller method but it's not working, not returning the updated one in controller.
Controller:-
@GetMapping
@RequestMapping("/demo")
public ResponseEntity<String> getEmployee(HttpServletRequest request) {
System.out.println("Header, application-name"+request.getHeader("application-name"));
return new ResponseEntity<>("Success", HttpStatus.OK);
}
Spring AOP code,
@Aspect
@Component
public class AOPExample {
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping) ||"
+ "@annotation(org.springframework.web.bind.annotation.PostMapping)")
public void controllerRequestMapping() {}
@Before("controllerRequestMapping()")
public HttpServletRequest advice(JoinPoint jp) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
String header = request.getHeader("application-name");
if (header == null) {
HttpServletRequestWrapperClass wrappedRequest = new HttpServletRequestWrapperClass(request);
wrappedRequest.putHeader("application-name", "Unknown");
request = wrappedRequest;
} else {
//validate application name
//400 - throw bad request exception
}
System.out.println("After setting---"+request.getHeader("application-name"));
return request;
}
}
Finally I resolved the issue,
Instead of using @Before advice used @Around advice, Around advice should return the object using proceed method.
@Aspect
@Component
public class AOPExample {
@Pointcut("@annotation(org.springframework.web.bind.annotation.GetMapping) ||"
+ "@annotation(org.springframework.web.bind.annotation.PostMapping)")
public void controllerRequestMapping() {}
@Around("controllerRequestMapping()")
public Object advice(ProceedingJoinPoint jp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
.getRequest();
String header = request.getHeader("application-name");
System.out.println("Header in AOP"+header);
if (header == null) {
HttpServletRequestWrapperClass wrappedRequest = new HttpServletRequestWrapperClass(request);
wrappedRequest.putHeader("application-name", "Unknown");
request = wrappedRequest;
} else {
//validate application name
//400 - throw bad request exception
//throw new BadRequestException("Invalid application name");
}
System.out.println("After setting---"+request.getHeader("application-name"));
return jp.proceed(new Object[] {request});
}
}
Updated httpservlet request is getting in controller method. Thanks