private static void completeOperationThrows(
      CollectInfo collectInfo,
      Operation operation,
      MethodAnnotationInfo mai,
      List<? extends IntrospectionHelper> introspectionHelper) {
    Class<?>[] thrownClasses = mai.getJavaMethod().getExceptionTypes();
    if (thrownClasses != null) {
      for (Class<?> thrownClass : thrownClasses) {
        ThrowableAnnotationInfo throwableAnnotationInfo =
            AnnotationUtils.getInstance().getThrowableAnnotationInfo(thrownClass);
        if (throwableAnnotationInfo != null) {
          int statusCode = throwableAnnotationInfo.getStatus().getCode();
          Response response = new Response();
          response.setCode(statusCode);
          response.setName(Status.valueOf(statusCode).getReasonPhrase());
          response.setMessage("Status " + statusCode);

          Class<?> outputPayloadType =
              throwableAnnotationInfo.isSerializable() ? thrownClass : StatusInfo.class;
          TypeInfo outputTypeInfo = null;
          try {
            outputTypeInfo = Types.getTypeInfo(outputPayloadType, null);
          } catch (UnsupportedTypeException e) {
            LOGGER.warning(
                "Could not add output payload for exception "
                    + thrownClass
                    + " throws by method "
                    + mai.getJavaMethod()
                    + ". "
                    + e.getMessage());
            continue;
          }

          RepresentationCollector.addRepresentation(
              collectInfo, outputTypeInfo, introspectionHelper);

          PayLoad outputPayLoad = new PayLoad();
          outputPayLoad.setType(outputTypeInfo.getRepresentationName());
          response.setOutputPayLoad(outputPayLoad);
          operation.getResponses().add(response);
        }
      }
    }
  }
  private static void completeOperationOutput(
      CollectInfo collectInfo,
      Operation operation,
      MethodAnnotationInfo mai,
      List<? extends IntrospectionHelper> introspectionHelper) {
    Response response = new Response();

    if (mai.getJavaMethod().getReturnType() != Void.TYPE) {
      TypeInfo outputTypeInfo;
      try {
        outputTypeInfo =
            Types.getTypeInfo(
                mai.getJavaMethod().getReturnType(), mai.getJavaMethod().getGenericReturnType());
      } catch (UnsupportedTypeException e) {
        LOGGER.warning(
            "Could not add output representation of method "
                + mai.getJavaMethod()
                + ". "
                + e.getMessage());
        return;
      }
      // Output representation
      RepresentationCollector.addRepresentation(collectInfo, outputTypeInfo, introspectionHelper);

      PayLoad outputEntity = new PayLoad();
      outputEntity.setType(outputTypeInfo.getRepresentationName());
      outputEntity.setArray(outputTypeInfo.isList());

      response.setOutputPayLoad(outputEntity);

      response.setCode(Status.SUCCESS_OK.getCode());
      response.setName(Status.SUCCESS_OK.getReasonPhrase());
      response.setDescription("");
      response.setMessage(Status.SUCCESS_OK.getDescription());
    } else {
      response.setCode(Status.SUCCESS_NO_CONTENT.getCode());
      response.setName(Status.SUCCESS_NO_CONTENT.getReasonPhrase());
      response.setDescription("");
      response.setMessage(Status.SUCCESS_NO_CONTENT.getDescription());
    }

    operation.getResponses().add(response);
  }
  public static void collectResource(
      CollectInfo collectInfo,
      ServerResource sr,
      String basePath,
      ChallengeScheme scheme,
      List<? extends IntrospectionHelper> introspectionHelper) {
    Resource resource = getResource(collectInfo, sr, basePath, scheme);

    // add operations
    ArrayList<Operation> operations = new ArrayList<>();

    List<AnnotationInfo> annotations =
        sr.isAnnotated() ? AnnotationUtils.getInstance().getAnnotations(sr.getClass()) : null;

    if (annotations != null) {
      for (AnnotationInfo annotationInfo : annotations) {
        if (annotationInfo instanceof MethodAnnotationInfo) {
          MethodAnnotationInfo methodAnnotationInfo = (MethodAnnotationInfo) annotationInfo;

          Method method = methodAnnotationInfo.getRestletMethod();

          Operation operation = getOperationFromMethod(method);

          if (StringUtils.isNullOrEmpty(operation.getName())) {
            operation.setName(methodAnnotationInfo.getJavaMethod().getName());
          }

          completeOperation(collectInfo, operation, methodAnnotationInfo, sr, introspectionHelper);

          for (IntrospectionHelper helper : introspectionHelper) {
            List<Class<?>> representationClasses =
                helper.processOperation(
                    resource, operation, sr.getClass(), methodAnnotationInfo.getJavaMethod());
            if (representationClasses != null && !representationClasses.isEmpty()) {
              for (Class<?> representationClazz : representationClasses) {
                TypeInfo typeInfo;
                try {
                  typeInfo = Types.getTypeInfo(representationClazz, null);
                } catch (UnsupportedTypeException e) {
                  LOGGER.warning(
                      "Could not add representation class "
                          + representationClazz.getName()
                          + ". "
                          + e.getMessage());
                  continue;
                }
                RepresentationCollector.addRepresentation(
                    collectInfo, typeInfo, introspectionHelper);
              }
            }
          }
          operations.add(operation);
        }
      }
      if (!operations.isEmpty()) {
        sortOperationsByMethod(operations);
        resource.setOperations(operations);
        addSectionsForResource(collectInfo, resource);
        collectInfo.addResource(resource);
      } else {
        LOGGER.warning("Resource " + resource.getName() + " has no methods.");
      }
    } else {
      LOGGER.warning("Resource " + resource.getName() + " has no methods.");
    }

    for (IntrospectionHelper helper : introspectionHelper) {
      helper.processResource(resource, sr.getClass());
    }
  }
  private static void completeOperationInput(
      CollectInfo collectInfo,
      Operation operation,
      MethodAnnotationInfo mai,
      ServerResource sr,
      List<? extends IntrospectionHelper> introspectionHelper,
      MetadataService metadataService) {
    Class<?>[] inputClasses = mai.getJavaMethod().getParameterTypes();
    if (inputClasses != null && inputClasses.length > 0) {

      // Input representation
      // Handles only the first method parameter
      TypeInfo inputTypeInfo;
      try {
        inputTypeInfo =
            Types.getTypeInfo(inputClasses[0], mai.getJavaMethod().getGenericParameterTypes()[0]);
      } catch (UnsupportedTypeException e) {
        LOGGER.warning(
            "Could not add input representation of method"
                + mai.getJavaMethod()
                + ". "
                + e.getMessage());
        return;
      }

      RepresentationCollector.addRepresentation(collectInfo, inputTypeInfo, introspectionHelper);

      PayLoad inputEntity = new PayLoad();
      inputEntity.setType(inputTypeInfo.getRepresentationName());
      inputEntity.setArray(inputTypeInfo.isList());
      operation.setInputPayLoad(inputEntity);

      // Consumes
      if (metadataService != null) {

        try {
          List<Variant> requestVariants =
              mai.getRequestVariants(metadataService, sr.getConverterService());

          if (requestVariants == null || requestVariants.isEmpty()) {
            LOGGER.warning(
                "Could not add consumes of method "
                    + mai.getJavaMethod()
                    + ". There is no requested variant");
            return;
          }

          // une representation per variant ?
          for (Variant variant : requestVariants) {

            if (variant.getMediaType() == null) {
              LOGGER.warning("Variant has no media type: " + variant);
              continue;
            }

            operation.getConsumes().add(variant.getMediaType().getName());
          }
        } catch (IOException e) {
          throw new ResourceException(e);
        }
      }
    }
  }