Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to conditionally assign the value of Required in @RequestParam?

I have 2 @RequestParam parameters in my Controller. I want to set the Required value of both the parameters based on a Condition. The condition could be like, if one of the parameter is passed, the other has to passed. So set the required of other as true and vice-versa. Otherwise set both false if none of the parameters are passed.

@RestController
public class TestController {

@GetMapping("/test")
public void test(@RequestParam(value = "a", required = (b !=null) String a, 
@RequestParam(value = "b", required = (a !=null) )  String b,) {
     {

     }

}

The syntax of using the variable name inside @RequestParam() is wrong, but I wanted to explain what I want.

like image 890
Mohammed Shirhaan Avatar asked Feb 04 '19 10:02

Mohammed Shirhaan


1 Answers

You can do it using one of the 2 following ways:

  1. Using Spring AOP and create a surrounding aspect for that request mapping
  2. Using HandlerInterceptorAdapter to intercept the requests for a given URI

1. Using Spring AOP

Create an annotation like the following:

public @interface RequestParameterPairValidation {

}

Then you can annotate your request mapping method with it:

@GetMapping("/test")
@RequestParameterPairValidation
public void test(
   @RequestParam(value = "a", required = false) String a, 
   @RequestParam(value = "b", required = false)  String b) {
      // API code goes here...
}

Create an aspect around the annotation. Something like:

@Aspect
@Component
public class RequestParameterPairValidationAspect {
    @Around("@annotation(x.y.z.RequestParameterPairValidation) && execution(public * *(..))")
    public Object time(final ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] requestMappingArgs = joinPoint.getArgs();
        String a = (String) requestMappingArgs[0];
        String b = (String) requestMappingArgs[1];

        boolean requestIsValid = //... execute validation logic here

        if (requestIsValid) {
           return joinPoint.proceed();
        } else {
           throw new IllegalArgumentException("illegal request");
        }
    }
}

Note that it would be a good option to return 400 BAD REQUEST here since the request was not valid. Depends on the context, of course, but this is a general rule of thumb to start with.

2. Using HandlerInterceptorAdapter

Create a new interceptor mapping to your desired URI (in this case /test):

@Configuration  
public class CustomInterceptor extends WebMvcConfigurerAdapter  {  

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
       registry
         .addInterceptor(new CustomRequestParameterPairInterceptor())
         .addPathPatterns("/test");
    }
} 

Define the logic for validation inside the custom interceptor:

public class CustomRequestParameterPairInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object obj, Exception exception) throws Exception {

    }

    @Override
    public void postHandle(HttpServletRequest req, HttpServletResponse res, Object obj, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
       // Run your validation logic here
    }
}

I would say the 2nd option is the best one since you can directly control the answer of the request. In this case it might be a 400 BAD REQUEST, or anything else that makes more sense in your case.

like image 89
João Dias Amaro Avatar answered Oct 19 '22 12:10

João Dias Amaro