11

I have a web service written in Spring MVC. It can be used by 3rd party developers. Our methods have a lot of optional parameters (passed in the query string).

I want to make sure that all the query string parameters are spelled correctly and there is no typos. Is there an easy way to do it? Method signature example:

 @RequestMapping(value = {"/filter"}, method = RequestMethod.GET) @ResponseBody public List<MetricType> getMetricTypes( @RequestParam(value = "subject", required = false) Long subjectId, @RequestParam(value = "area", required = false) Long areaId, @RequestParam(value = "onlyImmediateChildren", required = false) Boolean onlyImmediateChildren, @RequestParam(value = "componentGroup", required = false) Long componentGroupId ) throws Exception { //Some code } 

If somebody calls this method with "onlyImediateChildren=true" parameter (a typo) instead of "onlyImmediateChildren=true", Spring MVC will ignore the typoed parameter and will assume "onlyImmediateChildren" is null. Developer will get slightly incorrect list of results and will not notice the error. Such issues could be widespread and difficult to diagnose. I want to check there is no typoed params in query string to prevent such issues.

UPDATE

It is possible to extract the list of actual parameters from the query string. Then it could be compared with the list of the allowed parameters. If I hardcode the allowed parameter list, it will duplicate the method signature. I wonder if it is easy to extract a list of allowed parameters from the method signature (e.g. by @RequestParam annotation)?

Many thanks

Maxim

2
  • Which version of Spring are you using? Commented Apr 4, 2012 at 11:30
  • Do you mean spring MVC? I use file called "Spring-webmvc.3.0.5.Release.jar. " Commented Apr 4, 2012 at 12:02

4 Answers 4

6

You could implement your own HandlerInterceptor. In preHandle method you can obtain all HandlerMethod's parameters annotated with @RequestParameter. These will be all allowed parameters in request.

Sign up to request clarification or add additional context in comments.

1 Comment

Looks interesting. Will try to implement. I hope it will work.
2

Here is my implementation of an HandlerInterceptor which will only accept the parameters which are explicitely defined by a parameter annotation:

import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletResponse import org.springframework.http.HttpStatus import org.springframework.stereotype.Component import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.method.HandlerMethod import org.springframework.web.servlet.HandlerInterceptor /** * Interceptor which assures that only expected [RequestParam]s are send. */ @Component class UnexpectedParameterHandler : HandlerInterceptor { override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { if (handler is HandlerMethod) { val queryParams = request.parameterNames.toList() val expectedParams = handler.methodParameters .map { methodParameter -> val requestParamName = methodParameter.getParameterAnnotation(RequestParam::class.java)?.name val parameterName = methodParameter.parameter.name requestParamName ?: parameterName } val unknownParameters = queryParams.minus(expectedParams) if (unknownParameters.isNotEmpty()) { response.writer.write("unexpected parameter $unknownParameters") response.status = HttpStatus.BAD_REQUEST.value() return false } } return super.preHandle(request, response, handler) } } 

2 Comments

Thanks! Note that this seems to have one flaw: if you pass an invalid query parameter that just happens to have the same name as a path parameter that does exist, there won't be an error. I was able to fix that by using mapNotNull and not falling back to methodParameter.parameter.name.
This also seems to interfere with Spring Boot's built in BasicErrorController. I.e. you end up with a misleading error message for query parameters that do exist, but whose values are invalid (invalid enum value etc). I'm now checking that request.dispatcherType == DispatcherType.REQUEST to prevent this.
1

You could use the getParameterMap method of the request to get a Map of all the submitted parameters, and validate the keys against a list of all allowed parameters. You should be able to get the request object by simply adding it to the method signature, e.g.:

public List<MetricType> getMetricTypes( HttpServletRequest request, @RequestParam(value = "subject", required = false) Long subjectId, ... ) throws Exception { 

8 Comments

Thank you for that! What I am trying to do is to avoid hardcoding/duplicating a list of allowed parameters. This list is already specified by the method signature. I want to extract a list of allowed parameters from the method signature.
Instead of calling request.getParameterMap you can use a @RequestParam Map<String, String> paramMap method parameter
@MaximEliseev The easiest way would be to require your clients to provide all parameters, but leave them empty when they're not necessary since then you can use @RequestMapping's params to ensure that only the given params are present. Alternatively, you could extend AnnotationMethodHandlerAdapter (or some other related class; I'm not sure) to implement your parameter validation.
@beerbajay - an interesting idea about extending AnnotationMethodHandlerAdapter. But then I will have to get allowed params from method signature anyway.
A third method would be to use something like this answer to get the current method, then using reflection to introspect the method.
|
1

Spring will inject all the query parameters present in the url string through the argument of type

@RequestParam Map<String,String> in your controller method, if present.

@RequestMapping(value = "", method = RequestMethod.GET, produces = {"application/json"}) public HttpEntity<PagedResources<WebProductResource>> findAll(@RequestParam Map<String, String> allRequestParams){ ... 

}

You can then validate the keys of the map yourself. For an "enterprisey" way to do that generically, see my answer here: How to check spring RestController for unknown query params?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.