Spring 4.3.0.RELEASE 不向@Controller注入Model和Request

Spring 4.3.0.RELEASE does not inject Model and Request to @Controller

下面的代码在 Spring 4.2.6.REALESE 上运行良好。现在,迁移后发生了一些变化,我开始在我的@Controller 中得到空值这是一个错误吗?

@Controller
@RequestMapping("/client")
public class ClientController {

  @RequestMapping(value = "test", method = RequestMethod.GET)
  public String test(Model model) { 
    // model is null at this point
    return "client/test";
  }
}

我分享了模型对象为空的经验。下面的代码在 4.3.0-RELEASE 之前运行良好。也许我们缺少一些新配置?

@Controller
@RequestMapping("/admin/pricelists")
public class PriceListsController  {

    @RequestMapping(value = "/")
    public String index(final Model model) {
        // Model is null in 4.3.0-RELEASE.
        ...
    }
}

简答:4.3.0.RELEASE 需要 Servlet 3.0+

更长的证明:

模型为空,因为一种为 org.springframework.ui.Model 找到合适的 ArgumentResolver 的方法找到了列表中的第一个 org.springframework.web.method.annotation.RequestParamMethodArgumentResolver 而不是 org.springframework.web.method.annotation.ModelMethodProcessor

这是代码形式 HandlerMethodArgumentResolverComposite 的无效部分

private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
    HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
    if (result == null) {
        for (HandlerMethodArgumentResolver methodArgumentResolver : this.argumentResolvers) {
            if (logger.isTraceEnabled()) {
                logger.trace("Testing if argument resolver [" + methodArgumentResolver + "] supports [" +
                        parameter.getGenericParameterType() + "]");
            }
            if (methodArgumentResolver.supportsParameter(parameter)) {
                result = methodArgumentResolver;
                this.argumentResolverCache.put(parameter, result);
                break;
            }
        }
    }
    return result;
}

RequestParamMethodArgumentResolver 在列表中排在第一位,它的 RequestParamMethodArgumentResolver.supportsParameter(MethodParameter parameter) returns 是因为这一行:

if (MultipartResolutionDelegate.isMultipartArgument(parameter)) {
                return true;
            }

然后在 MultipartResolutionDelegate:

public static boolean isMultipartArgument(MethodParameter parameter) {
    Class<?> paramType = parameter.getNestedParameterType();
    return (MultipartFile.class == paramType || isMultipartFileCollection(parameter) ||
            isMultipartFileArray(parameter) || servletPartClass == paramType ||
            isPartCollection(parameter) || isPartArray(parameter));
}

isPartCollection returns true 因为这个奇怪的比较等式的两边都是空值!!

private static boolean isPartCollection(MethodParameter methodParam) {
    return (servletPartClass == getCollectionParameterType(methodParam));
}

servletPartClass 为空,因为

private static Class<?> servletPartClass = null;

    static {
        try {
            servletPartClass = ClassUtils.forName("javax.servlet.http.Part",
                    MultipartResolutionDelegate.class.getClassLoader());
        }
        catch (ClassNotFoundException ex) {
            // Servlet 3.0 javax.servlet.http.Part type not available -
            // Part references simply not supported then.
        }
    }

这个 is fixed4.3.1

Spring Framework / SPR-14358
Failure to resolve @RequestMapping method arguments in Servlet 2.5 environments