Skip to content

Failure to resolve @RequestMapping method arguments in Servlet 2.5 environments [SPR-14358] #18930

@spring-projects-issues

Description

@spring-projects-issues

Dmitri Gabbasov opened SPR-14358 and commented

Given the following bean configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/mvc   http://www.springframework.org/schema/mvc/spring-mvc.xsd">
  <context:component-scan base-package="test" />
  <mvc:annotation-driven/>
</beans>

and the following controller:

package test;
// ...
@Controller
public class TestController {
  @RequestMapping("/home")
  @ResponseBody
  public String home(@RequestParam String param) {
    return param;
}

and using them in a Servlet 2.5 environment (e.g. Tomcat 6) will result in the following exception when a request is made to /home:

org.springframework.web.multipart.MultipartException: Current request is not a multipart request
        at org.springframework.web.method.annotation.RequestParamMethodArgumentResolver.handleMissingValue(RequestParamMethodArgumentResolver.java:188)
        at org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver.resolveArgument(AbstractNamedValueMethodArgumentResolver.java:104)
        at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:121)
        at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:128)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:114)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
        ...

This only occurs when Spring chooses to use the RequestMappingHandlerAdapter (as opposed to the deprecated AnnotationMethodHandlerAdapter).

The root cause of this seems to be in the (somewhat recent) MultipartResolutionDelegate class. Its servletPartClass field remains null in pre Servlet 3.0 environments, and some equality checks yield false positives due to that. For instance:

private static boolean isPartCollection(MethodParameter methodParam) {
	return (servletPartClass == getCollectionParameterType(methodParam));
}
private static Class<?> getCollectionParameterType(MethodParameter methodParam) {
	Class<?> paramType = methodParam.getNestedParameterType();
	if (Collection.class == paramType || List.class.isAssignableFrom(paramType)){
		Class<?> valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam);
		if (valueType != null) {
			return valueType;
		}
	}
	return null;
}

getCollectionParameterType returns null for non-collection parameters, which makes isPartCollection return true. The isPartArray method is plagued by the same issue (and maybe other places are too).


Affects: 4.3 GA

Issue Links:

Referenced from: commits dcb2c73

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions