private Boolean getAnnotatedRequired(MethodParameter methodParameter) {
    System.out.println("*** methodParameter: " + methodParameter.getParameterName());

    Set<Boolean> requiredSet = new HashSet<Boolean>();
    Annotation[] methodAnnotations = methodParameter.getParameterAnnotations();

    // when the type is Optional, the required property of @RequestParam/@RequestHeader doesn't
    // matter,
    // since the value is always a non-null Optional after conversion
    boolean optional = isOptional(methodParameter);

    for (Annotation annotation : methodAnnotations) {

      if (annotation instanceof RequestParam) {
        requiredSet.add(!optional && isRequired((RequestParam) annotation));
      } else if (annotation instanceof RequestHeader) {
        requiredSet.add(!optional && ((RequestHeader) annotation).required());
      } else if (annotation instanceof PathVariable) {
        requiredSet.add(true);
      } else if (annotation instanceof RequestBody) {
        requiredSet.add(!optional && ((RequestBody) annotation).required());
      } else if (annotation instanceof RequestPart) {
        requiredSet.add(!optional && ((RequestPart) annotation).required());
      } else if (annotation instanceof NotNull) {
        System.out.println("*** FOUND NOTNULL ANNOTATION");
        requiredSet.add(true);
      }
    }

    System.out.println("required: " + requiredSet.contains(true));

    return requiredSet.contains(true);
  }
 /**
  * Validate the model attribute if applicable.
  *
  * <p>The default implementation checks for {@code @javax.validation.Valid}.
  *
  * @param binder the DataBinder to be used
  * @param parameter the method parameter
  */
 protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
   Annotation[] annotations = parameter.getParameterAnnotations();
   for (Annotation annot : annotations) {
     if (annot.annotationType().getSimpleName().startsWith("Valid")) {
       Object hints = AnnotationUtils.getValue(annot);
       binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
     }
   }
 }
 private boolean validateParameter(MethodParameter parameter) {
   Annotation[] annotations = parameter.getParameterAnnotations();
   for (Annotation annot : annotations) {
     if (annot.annotationType().getSimpleName().startsWith("Valid")) {
       return true;
     }
   }
   return false;
 }
 /**
  * Whether to validate the given @{@link RequestBody} method argument. The default implementation
  * checks if the parameter is also annotated with {@code @Valid}.
  *
  * @param parameter the method argument for which to check if validation is needed
  * @param argumentValue the method argument value (instantiated with a message converter)
  * @return {@code true} if validation should be invoked, {@code false} otherwise.
  */
 protected boolean shouldValidate(MethodParameter parameter, Object argumentValue) {
   Annotation[] annotations = parameter.getParameterAnnotations();
   for (Annotation annot : annotations) {
     if ("Valid".equals(annot.annotationType().getSimpleName())) {
       return true;
     }
   }
   return false;
 }
 /**
  * Validate the model attribute if applicable.
  *
  * <p>The default implementation checks for {@code @javax.validation.Valid}.
  *
  * @param binder the DataBinder to be used
  * @param parameter the method parameter
  */
 protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
   Annotation[] annotations = parameter.getParameterAnnotations();
   for (Annotation ann : annotations) {
     Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);
     if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {
       Object hints =
           (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));
       Object[] validationHints =
           (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
       binder.validate(validationHints);
       break;
     }
   }
 }
 /**
  * Obtains the specified {@link Annotation} on the specified {@link MethodParameter}.
  *
  * @param annotationClass the class of the {@link Annotation} to find on the {@link
  *     MethodParameter}
  * @param parameter the {@link MethodParameter} to search for an {@link Annotation}
  * @return the {@link Annotation} that was found or null.
  */
 private <T extends Annotation> T findMethodAnnotation(
     Class<T> annotationClass, MethodParameter parameter) {
   T annotation = parameter.getParameterAnnotation(annotationClass);
   if (annotation != null) {
     return annotation;
   }
   Annotation[] annotationsToSearch = parameter.getParameterAnnotations();
   for (Annotation toSearch : annotationsToSearch) {
     annotation = AnnotationUtils.findAnnotation(toSearch.annotationType(), annotationClass);
     if (annotation != null) {
       return annotation;
     }
   }
   return null;
 }
 private void validate(WebDataBinder binder, MethodParameter parameter)
     throws MethodArgumentNotValidException {
   Annotation[] annotations = parameter.getParameterAnnotations();
   for (Annotation annot : annotations) {
     if (annot.annotationType().getSimpleName().startsWith("Valid")) {
       Object hints = AnnotationUtils.getValue(annot);
       binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
       BindingResult bindingResult = binder.getBindingResult();
       if (bindingResult.hasErrors()) {
         if (isBindingErrorFatal(parameter)) {
           throw new MethodArgumentNotValidException(parameter, bindingResult);
         }
       }
     }
   }
 }
 private String asString(HandlerMethod handlerMethod) {
   StringBuilder sb = new StringBuilder();
   sb.append("\nController:\n").append(handlerMethod.getBeanType().getSimpleName());
   sb.append("\nMethod:\n");
   sb.append(handlerMethod.getMethod().getReturnType().getSimpleName()).append(" ");
   sb.append(handlerMethod.getMethod().getName()).append("(");
   for (MethodParameter param : handlerMethod.getMethodParameters()) {
     param.initParameterNameDiscovery(this.parameterNameDiscoverer);
     for (Annotation annotation : param.getParameterAnnotations()) {
       sb.append(annotation).append(" ");
     }
     sb.append(param.getParameterType().getSimpleName()).append(" ");
     sb.append(param.getParameterName());
     if (param.getParameterIndex() < handlerMethod.getMethodParameters().length - 1) {
       sb.append(" ");
     }
   }
   sb.append(")\n");
   return sb.toString();
 }
    private Type determineInferredType() {
      if (this.method == null) {
        return null;
      }

      Type genericParameterType = null;

      for (int i = 0; i < this.method.getParameterCount(); i++) {
        MethodParameter methodParameter = new MethodParameter(this.method, i);
        /*
         * We're looking for a single non-annotated parameter, or one annotated with @Payload.
         * We ignore parameters with type Message because they are not involved with conversion.
         */
        if (isEligibleParameter(methodParameter)
            && (methodParameter.getParameterAnnotations().length == 0
                || methodParameter.hasParameterAnnotation(Payload.class))) {
          if (genericParameterType == null) {
            genericParameterType = methodParameter.getGenericParameterType();
            if (genericParameterType instanceof ParameterizedType) {
              ParameterizedType parameterizedType = (ParameterizedType) genericParameterType;
              if (parameterizedType.getRawType().equals(Message.class)) {
                genericParameterType =
                    ((ParameterizedType) genericParameterType).getActualTypeArguments()[0];
              }
            }
          } else {
            if (MessagingMessageListenerAdapter.this.logger.isDebugEnabled()) {
              MessagingMessageListenerAdapter.this.logger.debug(
                  "Ambiguous parameters for target payload for method "
                      + this.method
                      + "; no inferred type header added");
            }
            return null;
          }
        }
      }

      return genericParameterType;
    }
  private Object[] resolveInitBinderArguments(
      Object handler, Method initBinderMethod, WebDataBinder binder, NativeWebRequest webRequest)
      throws Exception {

    Class[] initBinderParams = initBinderMethod.getParameterTypes();
    Object[] initBinderArgs = new Object[initBinderParams.length];

    for (int i = 0; i < initBinderArgs.length; i++) {
      MethodParameter methodParam = new MethodParameter(initBinderMethod, i);
      methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
      GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
      String paramName = null;
      boolean paramRequired = false;
      String paramDefaultValue = null;
      String pathVarName = null;
      Annotation[] paramAnns = methodParam.getParameterAnnotations();

      for (Annotation paramAnn : paramAnns) {
        if (RequestParam.class.isInstance(paramAnn)) {
          RequestParam requestParam = (RequestParam) paramAnn;
          paramName = requestParam.value();
          paramRequired = requestParam.required();
          paramDefaultValue = requestParam.defaultValue();
          break;
        } else if (ModelAttribute.class.isInstance(paramAnn)) {
          throw new IllegalStateException(
              "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod);
        } else if (PathVariable.class.isInstance(paramAnn)) {
          PathVariable pathVar = (PathVariable) paramAnn;
          pathVarName = pathVar.value();
        }
      }

      if (paramName == null && pathVarName == null) {
        Object argValue = resolveCommonArgument(methodParam, webRequest);
        if (argValue != WebArgumentResolver.UNRESOLVED) {
          initBinderArgs[i] = argValue;
        } else {
          Class paramType = initBinderParams[i];
          if (paramType.isInstance(binder)) {
            initBinderArgs[i] = binder;
          } else if (BeanUtils.isSimpleProperty(paramType)) {
            paramName = "";
          } else {
            throw new IllegalStateException(
                "Unsupported argument ["
                    + paramType.getName()
                    + "] for @InitBinder method: "
                    + initBinderMethod);
          }
        }
      }

      if (paramName != null) {
        initBinderArgs[i] =
            resolveRequestParam(
                paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null);
      } else if (pathVarName != null) {
        initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null);
      }
    }

    return initBinderArgs;
  }
  @SuppressWarnings("unchecked")
  private Object[] resolveHandlerArguments(
      Method handlerMethod,
      Object handler,
      NativeWebRequest webRequest,
      ExtendedModelMap implicitModel)
      throws Exception {

    Class[] paramTypes = handlerMethod.getParameterTypes();
    Object[] args = new Object[paramTypes.length];

    for (int i = 0; i < args.length; i++) {
      MethodParameter methodParam = new MethodParameter(handlerMethod, i);
      methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
      GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
      String paramName = null;
      String headerName = null;
      boolean requestBodyFound = false;
      String cookieName = null;
      String pathVarName = null;
      String attrName = null;
      boolean required = false;
      String defaultValue = null;
      boolean validate = false;
      int found = 0;
      Annotation[] paramAnns = methodParam.getParameterAnnotations();

      for (Annotation paramAnn : paramAnns) {
        if (RequestParam.class.isInstance(paramAnn)) {
          RequestParam requestParam = (RequestParam) paramAnn;
          paramName = requestParam.value();
          required = requestParam.required();
          defaultValue = requestParam.defaultValue();
          found++;
        } else if (RequestHeader.class.isInstance(paramAnn)) {
          RequestHeader requestHeader = (RequestHeader) paramAnn;
          headerName = requestHeader.value();
          required = requestHeader.required();
          defaultValue = requestHeader.defaultValue();
          found++;
        } else if (RequestBody.class.isInstance(paramAnn)) {
          requestBodyFound = true;
          found++;
        } else if (CookieValue.class.isInstance(paramAnn)) {
          CookieValue cookieValue = (CookieValue) paramAnn;
          cookieName = cookieValue.value();
          required = cookieValue.required();
          defaultValue = cookieValue.defaultValue();
          found++;
        } else if (PathVariable.class.isInstance(paramAnn)) {
          PathVariable pathVar = (PathVariable) paramAnn;
          pathVarName = pathVar.value();
          found++;
        } else if (ModelAttribute.class.isInstance(paramAnn)) {
          ModelAttribute attr = (ModelAttribute) paramAnn;
          attrName = attr.value();
          found++;
        } else if (Value.class.isInstance(paramAnn)) {
          defaultValue = ((Value) paramAnn).value();
        } else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) {
          validate = true;
        }
      }

      if (found > 1) {
        throw new IllegalStateException(
            "Handler parameter annotations are exclusive choices - "
                + "do not specify more than one such annotation on the same parameter: "
                + handlerMethod);
      }

      if (found == 0) {
        Object argValue = resolveCommonArgument(methodParam, webRequest);
        if (argValue != WebArgumentResolver.UNRESOLVED) {
          args[i] = argValue;
        } else if (defaultValue != null) {
          args[i] = resolveDefaultValue(defaultValue);
        } else {
          Class paramType = methodParam.getParameterType();
          if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
            args[i] = implicitModel;
          } else if (SessionStatus.class.isAssignableFrom(paramType)) {
            args[i] = this.sessionStatus;
          } else if (Errors.class.isAssignableFrom(paramType)) {
            throw new IllegalStateException(
                "Errors/BindingResult argument declared "
                    + "without preceding model attribute. Check your handler method signature!");
          } else if (BeanUtils.isSimpleProperty(paramType)) {
            paramName = "";
          } else {
            attrName = "";
          }
        }
      }

      if (paramName != null) {
        args[i] =
            resolveRequestParam(
                paramName, required, defaultValue, methodParam, webRequest, handler);
      } else if (headerName != null) {
        args[i] =
            resolveRequestHeader(
                headerName, required, defaultValue, methodParam, webRequest, handler);
      } else if (requestBodyFound) {
        args[i] = resolveRequestBody(methodParam, webRequest, handler);
      } else if (cookieName != null) {
        args[i] =
            resolveCookieValue(
                cookieName, required, defaultValue, methodParam, webRequest, handler);
      } else if (pathVarName != null) {
        args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
      } else if (attrName != null) {
        WebDataBinder binder =
            resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
        boolean assignBindingResult =
            (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
        if (binder.getTarget() != null) {
          doBind(binder, webRequest, validate, !assignBindingResult);
        }
        args[i] = binder.getTarget();
        if (assignBindingResult) {
          args[i + 1] = binder.getBindingResult();
          i++;
        }
        implicitModel.putAll(binder.getBindingResult().getModel());
      }
    }

    return args;
  }
  /**
   * 得到参数列表
   *
   * @param method
   * @param model
   * @param request
   * @param response
   * @param c
   * @return
   */
  @SuppressWarnings("unchecked")
  public static Object[] getArgs(
      Method method,
      Map<String, Object> model,
      HttpServletRequest request,
      HttpServletResponse response,
      Class<?> c) {
    Class<?>[] paramTypes = method.getParameterTypes();
    Object[] args = new Object[paramTypes.length];
    Map<String, Object> argMap = new HashMap<String, Object>(args.length);
    Map<String, String> pathValues = null;
    PathPattern pathPattern = method.getAnnotation(PathPattern.class);
    if (pathPattern != null) {
      String path = request.getRequestURI();
      int index = path.lastIndexOf('.');
      if (index != -1) {
        path = path.substring(0, index);
        String[] patterns = pathPattern.patterns();
        pathValues = getPathValues(patterns, path);
      }
    }
    MapBindingResult errors = new MapBindingResult(argMap, "");
    ParameterNameDiscoverer parameterNameDiscoverer =
        new LocalVariableTableParameterNameDiscoverer();
    for (int i = 0; i < paramTypes.length; i++) {
      Class<?> paramType = paramTypes[i];

      MethodParameter methodParam = new MethodParameter(method, i);
      methodParam.initParameterNameDiscovery(parameterNameDiscoverer);
      GenericTypeResolver.resolveParameterType(methodParam, c.getClass());

      String paramName = methodParam.getParameterName();
      // map
      if (Map.class.isAssignableFrom(paramType)) {
        args[i] = model;
      }
      // HttpServletRequest
      else if (HttpServletRequest.class.isAssignableFrom(paramType)) {
        args[i] = request;
      }
      // HttpServletResponse
      else if (HttpServletResponse.class.isAssignableFrom(paramType)) {
        args[i] = response;
      }
      // HttpSession
      else if (HttpSession.class.isAssignableFrom(paramType)) {
        args[i] = request.getSession();
      }
      // Errors
      else if (Errors.class.isAssignableFrom(paramType)) {
        args[i] = errors;
      }
      // MultipartFile
      else if (MultipartFile.class.isAssignableFrom(paramType)) {
        MultipartFile[] files = resolveMultipartFiles(request, errors, paramName);
        if (files != null && files.length > 0) {
          args[i] = files[0];
        }
      }
      // MultipartFile[]
      else if (MultipartFile[].class.isAssignableFrom(paramType)) {
        args[i] = resolveMultipartFiles(request, errors, paramName);
      } else {
        // 简单数据类型
        if (BeanUtils.isSimpleProperty(paramType)) {
          SimpleTypeConverter converter = new SimpleTypeConverter();
          Object value;
          // 是否是数组
          if (paramType.isArray()) {
            value = request.getParameterValues(paramName);
          } else {
            Object[] parameterAnnotations = methodParam.getParameterAnnotations();
            value = null;
            if (parameterAnnotations != null && parameterAnnotations.length > 0) {
              if (pathValues != null && pathValues.size() > 0) {
                for (Object object : parameterAnnotations) {
                  if (PathVariable.class.isInstance(object)) {
                    PathVariable pv = (PathVariable) object;
                    if (StringUtils.isEmpty(pv.value())) {
                      value = pathValues.get(paramName);
                    } else {
                      value = pathValues.get(pv.value());
                    }
                    break;
                  }
                }
              }
            } else {
              value = request.getParameter(paramName);
            }
          }
          try {
            args[i] = converter.convertIfNecessary(value, paramType, methodParam);
            model.put(paramName, args[i]);
          } catch (TypeMismatchException e) {
            errors.addError(new FieldError(paramName, paramName, e.getMessage()));
          }
        } else {
          // 复杂数据类型POJO类
          if (paramType.isArray()) {
            ObjectArrayDataBinder binder =
                new ObjectArrayDataBinder(paramType.getComponentType(), paramName);
            args[i] = binder.bind(request);
            model.put(paramName, args[i]);
          } else {
            Object bindObject = BeanUtils.instantiateClass(paramType);
            SummerServletRequestDataBinder binder =
                new SummerServletRequestDataBinder(bindObject, paramName);
            binder.bind(request);
            BindException be = new BindException(binder.getBindingResult());
            List<FieldError> fieldErrors = be.getFieldErrors();
            for (FieldError fieldError : fieldErrors) {
              errors.addError(fieldError);
            }
            args[i] = binder.getTarget();
            model.put(paramName, args[i]);
          }
        }
      }
    }
    return args;
  }