/**
  * Gets parameter name of this action input parameter.
  *
  * @return name
  */
 public String getParameterName() {
   String ret;
   String parameterName = methodParameter.getParameterName();
   if (parameterName == null) {
     methodParameter.initParameterNameDiscovery(new LocalVariableTableParameterNameDiscoverer());
     ret = methodParameter.getParameterName();
   } else {
     ret = parameterName;
   }
   return ret;
 }
  /** Resolves the given {@link RequestBody @RequestBody} annotation. */
  @SuppressWarnings("unchecked")
  protected Object resolveRequestBody(
      MethodParameter methodParam, NativeWebRequest webRequest, Object handler) throws Exception {

    HttpInputMessage inputMessage = createHttpInputMessage(webRequest);
    Class paramType = methodParam.getParameterType();
    MediaType contentType = inputMessage.getHeaders().getContentType();
    if (contentType == null) {
      StringBuilder builder =
          new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType()));
      String paramName = methodParam.getParameterName();
      if (paramName != null) {
        builder.append(' ');
        builder.append(paramName);
      }
      throw new HttpMediaTypeNotSupportedException(
          "Cannot extract @RequestBody parameter ("
              + builder.toString()
              + "): no Content-Type found");
    }
    List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
    if (this.messageConverters != null) {
      for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
        allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
        if (messageConverter.canRead(paramType, contentType)) {
          return messageConverter.read(paramType, inputMessage);
        }
      }
    }
    throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
  }
  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);
  }
 private String determineHeaderExpression(
     Header headerAnnotation, MethodParameter methodParameter) {
   methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
   String headerName = null;
   String relativeExpression = "";
   String valueAttribute = headerAnnotation.value();
   if (!StringUtils.hasText(valueAttribute)) {
     headerName = methodParameter.getParameterName();
   } else if (valueAttribute.indexOf('.') != -1) {
     String tokens[] = valueAttribute.split("\\.", 2);
     headerName = tokens[0];
     if (StringUtils.hasText(tokens[1])) {
       relativeExpression = "." + tokens[1];
     }
   } else {
     headerName = valueAttribute;
   }
   Assert.notNull(
       headerName,
       "Cannot determine header name. Possible reasons: -debug is "
           + "disabled or header name is not explicitly provided via @Header annotation.");
   String headerRetrievalExpression = "headers['" + headerName + "']";
   String fullHeaderExpression = headerRetrievalExpression + relativeExpression;
   String fallbackExpression =
       (headerAnnotation.required())
           ? "T(org.springframework.util.Assert).isTrue(false, 'required header not available:  "
               + headerName
               + "')"
           : "null";
   return headerRetrievalExpression
       + " != null ? "
       + fullHeaderExpression
       + " : "
       + fallbackExpression;
 }
 private String getRequiredParameterName(MethodParameter methodParam) {
   String name = methodParam.getParameterName();
   if (name == null) {
     throw new IllegalStateException(
         "No parameter name specified for argument of type ["
             + methodParam.getParameterType().getName()
             + "], and no parameter name information found in class file either.");
   }
   return name;
 }
 private String getPartName(MethodParameter parameter) {
   RequestPart annot = parameter.getParameterAnnotation(RequestPart.class);
   String partName = (annot != null ? annot.value() : "");
   if (partName.length() == 0) {
     partName = parameter.getParameterName();
     Assert.notNull(
         partName,
         "Request part name for argument type ["
             + parameter.getParameterType().getName()
             + "] not specified, and parameter name information not found in class file either.");
   }
   return partName;
 }
 private Class<?> getHttpEntityType(MethodParameter methodParam) {
   Assert.isAssignable(HttpEntity.class, methodParam.getParameterType());
   ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType();
   if (type.getActualTypeArguments().length == 1) {
     Type typeArgument = type.getActualTypeArguments()[0];
     if (typeArgument instanceof Class) {
       return (Class<?>) typeArgument;
     } else if (typeArgument instanceof GenericArrayType) {
       Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType();
       if (componentType instanceof Class) {
         // Surely, there should be a nicer way to do this
         Object array = Array.newInstance((Class<?>) componentType, 0);
         return array.getClass();
       }
     }
   }
   throw new IllegalArgumentException(
       "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized");
 }
 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();
 }
  @Override
  public void contributeMethodArgument(
      MethodParameter parameter,
      Object value,
      UriComponentsBuilder builder,
      Map<String, Object> uriVariables,
      ConversionService conversionService) {

    if (Map.class.isAssignableFrom(parameter.getParameterType())) {
      return;
    }

    PathVariable annot = parameter.getParameterAnnotation(PathVariable.class);
    String name = StringUtils.isEmpty(annot.value()) ? parameter.getParameterName() : annot.value();

    if (conversionService != null) {
      value =
          conversionService.convert(value, new TypeDescriptor(parameter), STRING_TYPE_DESCRIPTOR);
    }

    uriVariables.put(name, value);
  }
  @SuppressWarnings({"unchecked", "rawtypes"})
  private Object readWithMessageConverters(
      MethodParameter methodParam, HttpInputMessage inputMessage, Class<?> paramType)
      throws Exception {

    MediaType contentType = inputMessage.getHeaders().getContentType();
    if (contentType == null) {
      StringBuilder builder =
          new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType()));
      String paramName = methodParam.getParameterName();
      if (paramName != null) {
        builder.append(' ');
        builder.append(paramName);
      }
      throw new HttpMediaTypeNotSupportedException(
          "Cannot extract parameter (" + builder.toString() + "): no Content-Type found");
    }

    List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
    if (this.messageConverters != null) {
      for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
        allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
        if (messageConverter.canRead(paramType, contentType)) {
          if (logger.isDebugEnabled()) {
            logger.debug(
                "Reading ["
                    + paramType.getName()
                    + "] as \""
                    + contentType
                    + "\" using ["
                    + messageConverter
                    + "]");
          }
          return messageConverter.read((Class) paramType, inputMessage);
        }
      }
    }
    throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
  }
  public Object resolveArgument(
      MethodParameter parameter,
      ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest,
      WebDataBinderFactory binderFactory)
      throws Exception {

    HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
    NoodleRequestParam requestParam = parameter.getParameterAnnotation(NoodleRequestParam.class);

    String input = request.getParameter(requestParam.name());
    if (input != null && !input.isEmpty()) {
      if (logger.isDebugEnabled()) {
        logger.debug("resolveArgument -> input string -> " + input);
      }
      if (requestParam.type().equals("json")) {
        return JSON.parseObject(input, parameter.getParameterType());
      } else if (requestParam.type().equals("date")) {
        String param = request.getParameter(parameter.getParameterName());
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = simpleDateFormat.parse(param);
        return date;
      }
    } else {
      if (logger.isDebugEnabled()) {
        logger.debug("resolveArgument -> input string -> null");
      }
      Class<?> parameterType = parameter.getParameterType();
      if (parameterType.getConstructors().length > 0) {
        return parameterType.newInstance();
      } else {
        String className = parameterType.getCanonicalName();
        Class<?> T = Class.forName(className.substring(0, className.length() - 2));
        return (Object[]) Array.newInstance(T, (int) 0);
      }
    }

    return null;
  }
  /**
   * 得到参数列表
   *
   * @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;
  }
 private boolean isOptional(MethodParameter methodParameter) {
   System.out.println("isOptional: " + methodParameter.getParameterName());
   return methodParameter.getParameterType().getName().equals("java.util.Optional");
 }