private Operation parseMethod(Method method) {
    Operation operation = new Operation();

    RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
    Class<?> responseClass = null;
    List<String> produces = new ArrayList<String>();
    List<String> consumes = new ArrayList<String>();
    String responseContainer = null;
    String operationId = method.getName();
    Map<String, Property> defaultResponseHeaders = null;
    Set<Map<String, Object>> customExtensions = null;

    ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);

    if (apiOperation.hidden()) return null;
    if (!"".equals(apiOperation.nickname())) operationId = apiOperation.nickname();

    defaultResponseHeaders = parseResponseHeaders(apiOperation.responseHeaders());

    operation.summary(apiOperation.value()).description(apiOperation.notes());

    customExtensions = parseCustomExtensions(apiOperation.extensions());
    if (customExtensions != null) {
      for (Map<String, Object> extension : customExtensions) {
        if (extension != null) {
          for (Map.Entry<String, Object> map : extension.entrySet()) {
            operation.setVendorExtension(
                map.getKey().startsWith("x-") ? map.getKey() : "x-" + map.getKey(), map.getValue());
          }
        }
      }
    }

    if (apiOperation.response() != null && !Void.class.equals(apiOperation.response()))
      responseClass = apiOperation.response();
    if (!"".equals(apiOperation.responseContainer()))
      responseContainer = apiOperation.responseContainer();

    /// security
    if (apiOperation.authorizations() != null) {
      List<SecurityRequirement> securities = new ArrayList<SecurityRequirement>();
      for (Authorization auth : apiOperation.authorizations()) {
        if (auth.value() != null && !"".equals(auth.value())) {
          SecurityRequirement security = new SecurityRequirement();
          security.setName(auth.value());
          AuthorizationScope[] scopes = auth.scopes();
          for (AuthorizationScope scope : scopes) {
            if (scope.scope() != null && !"".equals(scope.scope())) {
              security.addScope(scope.scope());
            }
          }
          securities.add(security);
        }
      }
      if (securities.size() > 0) {
        for (SecurityRequirement sec : securities) operation.security(sec);
      }
    }

    if (responseClass == null) {
      // pick out response from method declaration
      LOG.info("picking up response class from method " + method);
      Type t = method.getGenericReturnType();
      responseClass = method.getReturnType();
      if (responseClass.equals(ResponseEntity.class)) {
        responseClass = getGenericSubtype(method.getReturnType(), method.getGenericReturnType());
      }
      if (!responseClass.equals(Void.class)
          && !"void".equals(responseClass.toString())
          && responseClass.getAnnotation(Api.class) == null) {
        LOG.info("reading model " + responseClass);
        Map<String, Model> models = ModelConverters.getInstance().readAll(t);
      }
    }
    if (responseClass != null
        && !responseClass.equals(Void.class)
        && !responseClass.equals(ResponseEntity.class)
        && responseClass.getAnnotation(Api.class) == null) {
      if (isPrimitive(responseClass)) {
        Property responseProperty = null;
        Property property = ModelConverters.getInstance().readAsProperty(responseClass);
        if (property != null) {
          if ("list".equalsIgnoreCase(responseContainer))
            responseProperty = new ArrayProperty(property);
          else if ("map".equalsIgnoreCase(responseContainer))
            responseProperty = new MapProperty(property);
          else responseProperty = property;
          operation.response(
              200,
              new Response()
                  .description("successful operation")
                  .schema(responseProperty)
                  .headers(defaultResponseHeaders));
        }
      } else if (!responseClass.equals(Void.class) && !"void".equals(responseClass.toString())) {
        Map<String, Model> models = ModelConverters.getInstance().read(responseClass);
        if (models.size() == 0) {
          Property pp = ModelConverters.getInstance().readAsProperty(responseClass);
          operation.response(
              200,
              new Response()
                  .description("successful operation")
                  .schema(pp)
                  .headers(defaultResponseHeaders));
        }
        for (String key : models.keySet()) {
          Property responseProperty = null;

          if ("list".equalsIgnoreCase(responseContainer))
            responseProperty = new ArrayProperty(new RefProperty().asDefault(key));
          else if ("map".equalsIgnoreCase(responseContainer))
            responseProperty = new MapProperty(new RefProperty().asDefault(key));
          else responseProperty = new RefProperty().asDefault(key);
          operation.response(
              200,
              new Response()
                  .description("successful operation")
                  .schema(responseProperty)
                  .headers(defaultResponseHeaders));
          swagger.model(key, models.get(key));
        }
        models = ModelConverters.getInstance().readAll(responseClass);
        for (String key : models.keySet()) {
          swagger.model(key, models.get(key));
        }
      }
    }

    operation.operationId(operationId);

    if (requestMapping.produces() != null) {
      for (String str : Arrays.asList(requestMapping.produces())) {
        if (!produces.contains(str)) {
          produces.add(str);
        }
      }
    }
    if (requestMapping.consumes() != null) {
      for (String str : Arrays.asList(requestMapping.consumes())) {
        if (!consumes.contains(str)) {
          consumes.add(str);
        }
      }
    }

    ApiResponses responseAnnotation = method.getAnnotation(ApiResponses.class);
    if (responseAnnotation != null) {
      updateApiResponse(operation, responseAnnotation);
    } else {
      ResponseStatus responseStatus = method.getAnnotation(ResponseStatus.class);
      if (responseStatus != null) {
        operation.response(
            responseStatus.value().value(), new Response().description(responseStatus.reason()));
      }
    }

    boolean isDeprecated = false;
    Deprecated annotation = method.getAnnotation(Deprecated.class);
    if (annotation != null) isDeprecated = true;

    boolean hidden = false;
    if (apiOperation != null) hidden = apiOperation.hidden();

    // process parameters
    Class[] parameterTypes = method.getParameterTypes();
    Type[] genericParameterTypes = method.getGenericParameterTypes();
    Annotation[][] paramAnnotations = method.getParameterAnnotations();
    // paramTypes = method.getParameterTypes
    // genericParamTypes = method.getGenericParameterTypes
    for (int i = 0; i < parameterTypes.length; i++) {
      Type type = genericParameterTypes[i];
      List<Annotation> annotations = Arrays.asList(paramAnnotations[i]);
      List<Parameter> parameters = getParameters(type, annotations);

      for (Parameter parameter : parameters) {
        operation.parameter(parameter);
      }
    }

    if (operation.getResponses() == null) {
      operation.defaultResponse(new Response().description("successful operation"));
    }

    // Process @ApiImplicitParams
    this.readImplicitParameters(method, operation);

    return operation;
  }
  public void processOperation(
      String resourcePath,
      String httpMethod,
      Operation operation,
      Map<String, List<CodegenOperation>> operations,
      Path path) {
    if (operation != null) {
      if (System.getProperty("debugOperations") != null) {
        LOGGER.info(
            "processOperation: resourcePath= "
                + resourcePath
                + "\t;"
                + httpMethod
                + " "
                + operation
                + "\n");
      }
      List<String> tags = operation.getTags();
      if (tags == null) {
        tags = new ArrayList<String>();
        tags.add("default");
      }

      /*
       build up a set of parameter "ids" defined at the operation level
       per the swagger 2.0 spec "A unique parameter is defined by a combination of a name and location"
        i'm assuming "location" == "in"
      */
      Set<String> operationParameters = new HashSet<String>();
      if (operation.getParameters() != null) {
        for (Parameter parameter : operation.getParameters()) {
          operationParameters.add(generateParameterId(parameter));
        }
      }

      // need to propagate path level down to the operation
      if (path.getParameters() != null) {
        for (Parameter parameter : path.getParameters()) {
          // skip propagation if a parameter with the same name is already defined at the operation
          // level
          if (!operationParameters.contains(generateParameterId(parameter))) {
            operation.addParameter(parameter);
          }
        }
      }

      for (String tag : tags) {
        CodegenOperation co = null;
        try {
          co =
              config.fromOperation(
                  resourcePath, httpMethod, operation, swagger.getDefinitions(), swagger);
          co.tags = new ArrayList<String>();
          co.tags.add(sanitizeTag(tag));
          config.addOperationToGroup(sanitizeTag(tag), resourcePath, operation, co, operations);

          List<Map<String, List<String>>> securities = operation.getSecurity();
          if (securities == null && swagger.getSecurity() != null) {
            securities = new ArrayList<Map<String, List<String>>>();
            for (SecurityRequirement sr : swagger.getSecurity()) {
              securities.add(sr.getRequirements());
            }
          }
          if (securities == null || securities.isEmpty()) {
            continue;
          }
          Map<String, SecuritySchemeDefinition> authMethods =
              new HashMap<String, SecuritySchemeDefinition>();
          // NOTE: Use only the first security requirement for now.
          // See the "security" field of "Swagger Object":
          //
          // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#swagger-object
          //  "there is a logical OR between the security requirements"
          if (securities.size() > 1) {
            LOGGER.warn("More than 1 security requirements are found, using only the first one");
          }
          Map<String, List<String>> security = securities.get(0);
          for (String securityName : security.keySet()) {
            SecuritySchemeDefinition securityDefinition = fromSecurity(securityName);
            if (securityDefinition != null) {
              if (securityDefinition instanceof OAuth2Definition) {
                OAuth2Definition oauth2Definition = (OAuth2Definition) securityDefinition;
                OAuth2Definition oauth2Operation = new OAuth2Definition();
                oauth2Operation.setType(oauth2Definition.getType());
                oauth2Operation.setAuthorizationUrl(oauth2Definition.getAuthorizationUrl());
                oauth2Operation.setFlow(oauth2Definition.getFlow());
                oauth2Operation.setTokenUrl(oauth2Definition.getTokenUrl());
                oauth2Operation.setScopes(new HashMap<String, String>());
                for (String scope : security.get(securityName)) {
                  if (oauth2Definition.getScopes().containsKey(scope)) {
                    oauth2Operation.addScope(scope, oauth2Definition.getScopes().get(scope));
                  }
                }
                authMethods.put(securityName, oauth2Operation);
              } else {
                authMethods.put(securityName, securityDefinition);
              }
            }
          }
          if (!authMethods.isEmpty()) {
            co.authMethods = config.fromSecurity(authMethods);
            co.hasAuthMethods = true;
          }
        } catch (Exception ex) {
          String msg =
              "Could not process operation:\n" //
                  + "  Tag: "
                  + tag
                  + "\n" //
                  + "  Operation: "
                  + operation.getOperationId()
                  + "\n" //
                  + "  Resource: "
                  + httpMethod
                  + " "
                  + resourcePath
                  + "\n" //
                  + "  Definitions: "
                  + swagger.getDefinitions()
                  + "\n" //
                  + "  Exception: "
                  + ex.getMessage();
          throw new RuntimeException(msg, ex);
        }
      }
    }
  }