Search code examples
springspring-bootspring-aopspring-aspects

How to get the updated/modified HttpServletRequest object from AOP @Before advice to Spring controller method


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;
     }
  }

Solution

  • 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