/** 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 UriComponents applyContributers(
      UriComponentsBuilder builder,
      Method method,
      Object[] argumentValues,
      Map<String, Object> uriVars) {

    if (this.contributors.isEmpty()) {
      return builder.buildAndExpand(uriVars);
    }

    int paramCount = method.getParameters().length;
    int argCount = argumentValues.length;

    Assert.isTrue(
        paramCount == argCount,
        "Number of method parameters "
            + paramCount
            + " does not match number of argument values "
            + argCount);

    for (int i = 0; i < paramCount; i++) {
      MethodParameter param = new MethodParameter(method, i);
      param.initParameterNameDiscovery(parameterNameDiscoverer);
      for (UriComponentsContributor c : this.contributors) {
        if (c.supportsParameter(param)) {
          c.contributeMethodArgument(
              param, argumentValues[i], builder, uriVars, this.conversionService);
          break;
        }
      }
    }

    return builder.buildAndExpand(uriVars);
  }
 private boolean isHypermediaDisabled(MethodParameter returnType) {
   return AnnotationUtils.findAnnotation(returnType.getMethod(), HypermediaDisabled.class)
           != null
       || AnnotationUtils.findAnnotation(
               returnType.getMethod().getDeclaringClass(), HypermediaDisabled.class)
           != null;
 }
 private String getDetailedErrorMessage(String message, MethodParameter param) {
   StringBuilder sb = new StringBuilder(message);
   sb.append("argument [" + param.getParameterIndex() + "] ");
   sb.append("of type [" + param.getParameterType().getName() + "] ");
   sb.append("on method [" + getBridgedMethod().toGenericString() + "]");
   return sb.toString();
 }
 /**
  * Extension point to setBasicInfoForCreate the model attribute if not found in the model. The
  * default implementation uses the default constructor.
  *
  * @param attributeName the name of the attribute, never {@code null}
  * @param parameter the method parameter
  * @param binderFactory for creating WebDataBinder instance
  * @param request the current request
  * @return the created model attribute, never {@code null}
  */
 protected Object createAttribute(
     String attributeName,
     MethodParameter parameter,
     WebDataBinderFactory binderFactory,
     NativeWebRequest request)
     throws Exception {
   String value = getRequestValueForAttribute(attributeName, request);
   if (value != null) {
     Object attribute =
         createAttributeFromRequestValue(value, attributeName, parameter, binderFactory, request);
     if (attribute != null) {
       return attribute;
     }
   }
   Class<?> parameterType = parameter.getParameterType();
   if (parameterType.isArray() || List.class.isAssignableFrom(parameterType)) {
     return ArrayList.class.newInstance();
   }
   if (Set.class.isAssignableFrom(parameterType)) {
     return HashSet.class.newInstance();
   }
   if (MapWapper.class.isAssignableFrom(parameterType)) {
     return MapWapper.class.newInstance();
   }
   return BeanUtils.instantiateClass(parameter.getParameterType());
 }
 /**
  * Whether to raise a {@link org.springframework.validation.BindException} on bind or validation
  * errors. The default implementation returns {@code true} if the next method argument is not of
  * type {@link org.springframework.validation.Errors}.
  *
  * @param binder the data binder used to perform data binding
  * @param parameter the method argument
  */
 protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
   int i = parameter.getParameterIndex();
   Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
   boolean hasBindingResult =
       (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
   return !hasBindingResult;
 }
 /**
  * Whether to raise a {@link MethodArgumentNotValidException} on validation errors.
  *
  * @param parameter the method argument
  * @return {@code true} if the next method argument is not of type {@link Errors}
  */
 private boolean isBindingErrorFatal(MethodParameter parameter) {
   int i = parameter.getParameterIndex();
   Class<?>[] paramTypes = parameter.getMethod().getParameterTypes();
   boolean hasBindingResult =
       (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1]));
   return !hasBindingResult;
 }
  @Override
  public Object resolveArgument(MethodParameter param, NativeWebRequest request) throws Exception {

    if (request.getNativeRequest() instanceof ClientDataRequest
        && param.hasParameterAnnotation(PortletRequestBody.class)) {
      String value = param.getParameterAnnotation(PortletRequestBody.class).value();
      ClientDataRequest clientDataRequest = request.getNativeRequest(ClientDataRequest.class);
      if (!PortletRequestBody.DEFAULT.equals(value)) {
        if (isMethod(clientDataRequest, RequestMethod.POST)) {
          String json =
              JSON_MAPPER.readTree(getRequestBody(clientDataRequest)).get(value).toString();
          return JSON_MAPPER.readValue(json, param.getParameterType());
        } else if (isMethod(clientDataRequest, RequestMethod.GET)) {
          return JSON_MAPPER.readValue(request.getParameter(value), param.getParameterType());
        }
        throw new RuntimeException(
            MessageFormat.format(
                "REST Method {0} for values not supported.", clientDataRequest.getMethod()));
      }
      if (isMethod(clientDataRequest, RequestMethod.POST)) {
        return JSON_MAPPER.readValue(clientDataRequest.getReader(), param.getParameterType());
      }
      throw new RuntimeException(
          MessageFormat.format(
              "REST Method {0} for body not supported.", clientDataRequest.getMethod()));
    }
    return WebArgumentResolver.UNRESOLVED;
  }
  /*
   * (non-Javadoc)
   *
   * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(
   * org.springframework.core.MethodParameter,
   * org.springframework.web.method.support.ModelAndViewContainer,
   * org.springframework.web.context.request.NativeWebRequest,
   * org.springframework.web.bind.support.WebDataBinderFactory)
   */
  @Override
  public Object resolveArgument(
      MethodParameter parameter,
      ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest,
      WebDataBinderFactory binderFactory)
      throws Exception {

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication == null) {
      return null;
    }
    Object details = authentication.getDetails();
    if (details != null && !parameter.getParameterType().isAssignableFrom(details.getClass())) {
      AuthenticationDetails authenticationDetails =
          findMethodAnnotation(AuthenticationDetails.class, parameter);
      if (authenticationDetails.errorOnInvalidType()) {
        throw new ClassCastException(
            details + " is not assiable to " + parameter.getParameterType());
      } else {
        return null;
      }
    }
    return details;
  }
  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);
  }
 /**
  * Resolve the argument from the model or if not found instantiate it with its default if it is
  * available. The model attribute is then populated with request values via data binding and
  * optionally validated if {@code @java.validation.Valid} is present on the argument.
  *
  * @throws org.springframework.validation.BindException if data binding and validation result in
  *     an error and the next method parameter is not of type {@link
  *     org.springframework.validation.Errors}.
  * @throws Exception if WebDataBinder initialization fails.
  */
 public final Object resolveArgument(
     MethodParameter parameter,
     ModelAndViewContainer mavContainer,
     NativeWebRequest request,
     WebDataBinderFactory binderFactory)
     throws Exception {
   String name = parameter.getParameterAnnotation(FormModel.class).value();
   Object target =
       (mavContainer.containsAttribute(name))
           ? mavContainer.getModel().get(name)
           : createAttribute(name, parameter, binderFactory, request);
   WebDataBinder binder = binderFactory.createBinder(request, target, name);
   target = binder.getTarget();
   if (target != null) {
     bindRequestParameters(mavContainer, binderFactory, binder, request, parameter);
     validateIfApplicable(binder, parameter);
     if (binder.getBindingResult().hasErrors()) {
       if (isBindExceptionRequired(binder, parameter)) {
         throw new BindException(binder.getBindingResult());
       }
     }
   }
   target = binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType());
   mavContainer.addAttribute(name, target);
   return target;
 }
 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;
 }
 @Override
 public boolean supportsParameter(MethodParameter parameter) {
   Class<?> paramType = parameter.getParameterType();
   return ((parameter.hasParameterAnnotation(Headers.class)
           && Map.class.isAssignableFrom(paramType))
       || MessageHeaders.class.equals(paramType)
       || MessageHeaderAccessor.class.isAssignableFrom(paramType));
 }
 @Override
 public boolean supports(
     MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
   returnType.increaseNestingLevel();
   Type nestedType = returnType.getNestedGenericParameterType();
   returnType.decreaseNestingLevel();
   return ResourceSupport.class.isAssignableFrom(returnType.getParameterType())
       || TypeUtils.isAssignable(ResourceSupport.class, nestedType);
 }
 /**
  * Return {@code true} if there is a method-level {@code @ModelAttribute} or if it is a non-simple
  * type when {@code annotationNotRequired=true}.
  */
 @Override
 public boolean supportsReturnType(MethodParameter returnType) {
   if (returnType.getMethodAnnotation(ModelAttribute.class) != null) {
     return true;
   } else if (this.annotationNotRequired) {
     return !BeanUtils.isSimpleProperty(returnType.getParameterType());
   } else {
     return false;
   }
 }
 /**
  * Determine whether the given dependency carries a value annotation.
  *
  * @see Value
  */
 public Object getSuggestedValue(DependencyDescriptor descriptor) {
   Object value = findValue(descriptor.getAnnotations());
   if (value == null) {
     MethodParameter methodParam = descriptor.getMethodParameter();
     if (methodParam != null) {
       value = findValue(methodParam.getMethodAnnotations());
     }
   }
   return value;
 }
 /**
  * @return true if the parameter is annotated with {@link ModelAttribute} or in default resolution
  *     mode also if it is not a simple type.
  */
 @Override
 public boolean supportsParameter(MethodParameter parameter) {
   if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
     return true;
   } else if (this.annotationNotRequired) {
     return !BeanUtils.isSimpleProperty(parameter.getParameterType());
   } else {
     return false;
   }
 }
 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;
 }
 @Override
 public boolean supportsReturnType(MethodParameter returnType) {
   if (ResponseBodyEmitter.class.isAssignableFrom(returnType.getParameterType())) {
     return true;
   } else if (ResponseEntity.class.isAssignableFrom(returnType.getParameterType())) {
     Class<?> bodyType = ResolvableType.forMethodParameter(returnType).getGeneric(0).resolve();
     return (bodyType != null && ResponseBodyEmitter.class.isAssignableFrom(bodyType));
   }
   return false;
 }
 /**
  * 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;
 }
 @Override
 public boolean supportsParameter(MethodParameter parameter) {
   if (!parameter.hasParameterAnnotation(PathVariable.class)) {
     return false;
   }
   if (Map.class.isAssignableFrom(parameter.getParameterType())) {
     String paramName = parameter.getParameterAnnotation(PathVariable.class).value();
     return StringUtils.hasText(paramName);
   }
   return true;
 }
  @Override
  protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest webRequest)
      throws Exception {
    Object arg = super.resolveName(name, parameter, webRequest);
    arg = tryUnJson(parameter, arg);

    if (createValidators(parameter.getMethod())) {
      validate(parameter.getMethod(), parameter.getParameterIndex(), arg);
    }

    return arg;
  }
  @Override
  public Mono<Object> resolveArgument(
      MethodParameter param, BindingContext bindingContext, ServerWebExchange exchange) {

    ResolvableType entityType = ResolvableType.forMethodParameter(param);
    MethodParameter bodyParameter = new MethodParameter(param);
    bodyParameter.increaseNestingLevel();

    return readBody(bodyParameter, false, bindingContext, exchange)
        .map(body -> createHttpEntity(body, entityType, exchange))
        .defaultIfEmpty(createHttpEntity(null, entityType, exchange));
  }
  @Override
  public ModelAndView resolveException(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception exp) {

    Map<String, Object> errorMap = new HashMap<>(2);
    if (handler instanceof HandlerMethod) {
      HandlerMethod handlerMethod = (HandlerMethod) handler;
      MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
      if (methodParameters != null && methodParameters.length > 0) {
        MethodParameter methodParameter = methodParameters[0];
        Class<?> controllerClass = methodParameter.getContainingClass();
        if (controllerClass.isAnnotationPresent(Channel.class)) {
          String channel = controllerClass.getAnnotation(Channel.class).value();
          if (ChannelSet.QUNAR.equals(channel)) {
            log.error("QUNAR异常处理:", exp);
            if (exp instanceof SQLException) {
              errorMap.put(QunarResultKey.errorCode.name(), QunarErrorCode.ERR_SQL.code());
              errorMap.put(QunarResultKey.errorMsg.name(), QunarErrorCode.ERR_SQL.value());
            }
            if (exp instanceof TradeException) {
              TradeException ex = (TradeException) exp;
              errorMap.put(QunarResultKey.errorCode.name(), ex.getReturnCode());
              errorMap.put(QunarResultKey.errorMsg.name(), ex.getReturnMessage());
            } else {
              errorMap.put(QunarResultKey.errorCode.name(), QunarErrorCode.ERR_PARAM.code());
              errorMap.put(QunarResultKey.errorMsg.name(), QunarErrorCode.ERR_PARAM.value());
            }
            log.error("去哪儿返回异常:" + JSON.toJSONString(errorMap));
            return new ModelAndView(new MappingJackson2JsonView(), errorMap);
          } else if (ChannelSet.CTRIP.equals(channel)) {
            log.error("CTRIP异常处理:", exp);
            if (exp instanceof TradeException) {
              TradeException ex = (TradeException) exp;
              errorMap.put(CTripResultKey.MsgCode.name(), ex.getReturnCode());
              errorMap.put(CTripResultKey.Message.name(), ex.getReturnMessage());
            } else {
              errorMap.put(CTripResultKey.MsgCode.name(), CTripErrorCode.ERROR.name());
              errorMap.put(CTripResultKey.Message.name(), CTripErrorCode.ERROR.value);
            }
            log.error("携程返回异常:" + JSON.toJSONString(errorMap));
            return new ModelAndView(new MappingJackson2JsonView(), errorMap);
          }
        }
      }
    }

    // do as default
    log.error("HBC标准异常处理:", exp);
    errorMap.put(StandardResultKey.status.name(), Integer.valueOf(RspStatus.ERROR.toString()));
    errorMap.put(StandardResultKey.message.name(), exp.toString());
    return new ModelAndView(new MappingJackson2JsonView(), errorMap);
  }
 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;
 }
 /**
  * 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;
 }
 @Override
 public boolean supportsParameter(MethodParameter parameter) {
   if (parameter.hasParameterAnnotation(FormModel.class)) {
     return true;
   }
   return false;
 }
  private WebDataBinder resolveModelAttribute(
      String attrName,
      MethodParameter methodParam,
      ExtendedModelMap implicitModel,
      NativeWebRequest webRequest,
      Object handler)
      throws Exception {

    // Bind request parameter onto object...
    String name = attrName;
    if ("".equals(name)) {
      name = Conventions.getVariableNameForParameter(methodParam);
    }
    Class<?> paramType = methodParam.getParameterType();
    Object bindObject;
    if (implicitModel.containsKey(name)) {
      bindObject = implicitModel.get(name);
    } else if (this.methodResolver.isSessionAttribute(name, paramType)) {
      bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
      if (bindObject == null) {
        raiseSessionRequiredException(
            "Session attribute '" + name + "' required - not found in session");
      }
    } else {
      bindObject = BeanUtils.instantiateClass(paramType);
    }
    WebDataBinder binder = createBinder(webRequest, bindObject, name);
    initBinder(handler, name, binder, webRequest);
    return binder;
  }
  protected Object resolveCommonArgument(
      MethodParameter methodParameter, NativeWebRequest webRequest) throws Exception {

    // Invoke custom argument resolvers if present...
    if (this.customArgumentResolvers != null) {
      for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) {
        Object value = argumentResolver.resolveArgument(methodParameter, webRequest);
        if (value != WebArgumentResolver.UNRESOLVED) {
          return value;
        }
      }
    }

    // Resolution of standard parameter types...
    Class paramType = methodParameter.getParameterType();
    Object value = resolveStandardArgument(paramType, webRequest);
    if (value != WebArgumentResolver.UNRESOLVED
        && !ClassUtils.isAssignableValue(paramType, value)) {
      throw new IllegalStateException(
          "Standard argument type ["
              + paramType.getName()
              + "] resolved to incompatible value of type ["
              + (value != null ? value.getClass() : null)
              + "]. Consider declaring the argument type in a less specific fashion.");
    }
    return value;
  }
 private ServletRequest prepareServletRequest(
     Object target, NativeWebRequest request, MethodParameter parameter) {
   String modelPrefixName = parameter.getParameterAnnotation(FormModel.class).value();
   HttpServletRequest nativeRequest = (HttpServletRequest) request.getNativeRequest();
   MultipartRequest multipartRequest =
       WebUtils.getNativeRequest(nativeRequest, MultipartRequest.class);
   MockHttpServletRequest mockRequest = null;
   if (multipartRequest != null) {
     MockMultipartHttpServletRequest mockMultipartRequest = new MockMultipartHttpServletRequest();
     for (MultipartFile file : multipartRequest.getFileMap().values()) {
       mockMultipartRequest.addFile(
           new MultipartFileWrapper(getNewParameterName(file.getName(), modelPrefixName), file));
     }
     mockRequest = mockMultipartRequest;
   } else {
     mockRequest = new MockHttpServletRequest();
   }
   for (Entry<String, String> entry : getUriTemplateVariables(request).entrySet()) {
     String parameterName = entry.getKey();
     String value = entry.getValue();
     if (isFormModelAttribute(parameterName, modelPrefixName)) {
       mockRequest.setParameter(getNewParameterName(parameterName, modelPrefixName), value);
     }
   }
   for (Object parameterEntry : nativeRequest.getParameterMap().entrySet()) {
     Entry<String, String[]> entry = (Entry<String, String[]>) parameterEntry;
     String parameterName = entry.getKey();
     String[] value = entry.getValue();
     if (isFormModelAttribute(parameterName, modelPrefixName)) {
       mockRequest.setParameter(getNewParameterName(parameterName, modelPrefixName), value);
     }
   }
   return mockRequest;
 }