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); } } } }