/**
   * Extract the value for an annotated-method parameter (see package {@link
   * org.wicketstuff.rest.annotations.parameters}).
   *
   * @param methodParameter the current method parameter.
   * @param pathParameters the values of path parameters for the current request.
   * @param annotation the annotation for the current parameter that indicates how to retrieve the
   *     value for the current parameter.
   * @param pageParameters PageParameters for the current request.
   * @return the extracted value.
   */
  private Object extractParameterValue(
      MethodParameter methodParameter,
      LinkedHashMap<String, String> pathParameters,
      Annotation annotation,
      PageParameters pageParameters) {
    Object paramValue = null;
    Class<?> argClass = methodParameter.getParameterClass();
    String mimeInputFormat = methodParameter.getOwnerMethod().getMimeInputFormat();

    if (annotation instanceof RequestBody)
      paramValue = deserializeObjectFromRequest(argClass, mimeInputFormat);
    else if (annotation instanceof PathParam)
      paramValue = toObject(argClass, pathParameters.get(((PathParam) annotation).value()));
    else if (annotation instanceof RequestParam)
      paramValue = extractParameterFromQuery(pageParameters, (RequestParam) annotation, argClass);
    else if (annotation instanceof HeaderParam)
      paramValue = extractParameterFromHeader((HeaderParam) annotation, argClass);
    else if (annotation instanceof CookieParam)
      paramValue = extractParameterFromCookies((CookieParam) annotation, argClass);
    else if (annotation instanceof MatrixParam)
      paramValue =
          extractParameterFromMatrixParams(pageParameters, (MatrixParam) annotation, argClass);

    return paramValue;
  }
  /**
   * * Invokes one of the resource methods annotated with {@link MethodMapping}.
   *
   * @param mappedMethod mapping info of the method.
   * @param attributes Attributes object for the current request.
   * @return the value returned by the invoked method
   */
  private Object invokeMappedMethod(MethodMappingInfo mappedMethod, Attributes attributes) {

    Method method = mappedMethod.getMethod();
    List parametersValues = new ArrayList();

    // Attributes objects
    PageParameters pageParameters = attributes.getParameters();
    WebResponse response = (WebResponse) attributes.getResponse();
    HttpMethod httpMethod = HttpUtils.getHttpMethod((WebRequest) RequestCycle.get().getRequest());

    LinkedHashMap<String, String> pathParameters =
        mappedMethod.populatePathParameters(pageParameters);
    Iterator<String> pathParamsIterator = pathParameters.values().iterator();
    Class<?>[] parameterTypes = method.getParameterTypes();

    for (int i = 0; i < parameterTypes.length; i++) {
      Object paramValue = null;
      MethodParameter methodParameter = new MethodParameter(parameterTypes[i], mappedMethod, i);
      Annotation annotation = ReflectionUtils.getAnnotationParam(i, method);
      // retrieve parameter value
      if (annotation != null)
        paramValue =
            extractParameterValue(methodParameter, pathParameters, annotation, pageParameters);
      else paramValue = extractParameterFromUrl(methodParameter, pathParamsIterator);
      // try to use the default value
      if (paramValue == null && !methodParameter.getDeaultValue().isEmpty())
        paramValue =
            toObject(methodParameter.getParameterClass(), methodParameter.getDeaultValue());

      if (paramValue == null && methodParameter.isRequired()) {
        response.sendError(
            400,
            "No suitable method found for URL '"
                + extractUrlFromRequest()
                + "' and HTTP method "
                + httpMethod);
        return null;
      }

      parametersValues.add(paramValue);
    }

    try {
      return method.invoke(this, parametersValues.toArray());
    } catch (Exception e) {
      response.sendError(500, "General server error.");
      throw new RuntimeException("Error invoking method '" + method.getName() + "'", e);
    }
  }
  /**
   * * Extract a parameter values from the rest URL.
   *
   * @param methodParameter the current method parameter.
   * @param pathParamIterator an iterator on the current values of path parameters.
   * @return the parameter value.
   */
  private Object extractParameterFromUrl(
      MethodParameter methodParameter, Iterator<String> pathParamIterator) {

    if (!pathParamIterator.hasNext()) return null;

    return toObject(methodParameter.getParameterClass(), pathParamIterator.next());
  }