From c2fd89852396ef35550d543b7714a1267c962cce Mon Sep 17 00:00:00 2001 From: Rafael Lopez Date: Tue, 6 Jun 2017 23:06:20 -0500 Subject: [PATCH] Components Merge and Schema changes calling the ModelConverter --- .../io/swagger/util/ParameterProcessor.java | 139 ++-- .../java/io/swagger/util/ReflectionUtils.java | 2 +- .../jaxrs2/DefaultParameterExtension.java | 2 +- .../io/swagger/jaxrs2/OperationParser.java | 415 +++++----- .../main/java/io/swagger/jaxrs2/Reader.java | 710 ++++++++++-------- .../swagger/jaxrs2/ext/OpenAPIExtensions.java | 5 +- .../java/io/swagger/jaxrs2/ReaderTest.java | 623 +++++++-------- .../jaxrs2/resources/BasicFieldsResource.java | 1 + .../resources/DuplicatedSecurityResource.java | 37 + pom.xml | 52 +- 10 files changed, 1027 insertions(+), 959 deletions(-) create mode 100644 modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/DuplicatedSecurityResource.java diff --git a/modules/swagger-core/src/main/java/io/swagger/util/ParameterProcessor.java b/modules/swagger-core/src/main/java/io/swagger/util/ParameterProcessor.java index 9996fbb104..8ca037f283 100644 --- a/modules/swagger-core/src/main/java/io/swagger/util/ParameterProcessor.java +++ b/modules/swagger-core/src/main/java/io/swagger/util/ParameterProcessor.java @@ -33,17 +33,17 @@ public class ParameterProcessor { static Logger LOGGER = LoggerFactory.getLogger(ParameterProcessor.class); - public static Parameter applyAnnotations(OpenAPI swagger, Parameter parameter, Type type, List annotations) { + public static Parameter applyAnnotations(OpenAPI openAPI, Parameter parameter, Type type, List annotations) { final AnnotationsHelper helper = new AnnotationsHelper(annotations, type); if (helper.isContext()) { return null; } - if(parameter == null) { + if (parameter == null) { return null; } final ParamWrapper param = null; - for(Annotation annotation : annotations) { + for (Annotation annotation : annotations) { if (annotation instanceof io.swagger.oas.annotations.Parameter) { io.swagger.oas.annotations.Parameter p = (io.swagger.oas.annotations.Parameter) annotation; if (StringUtils.isNotBlank(p.in())) { @@ -60,8 +60,6 @@ public static Parameter applyAnnotations(OpenAPI swagger, Parameter parameter, T } if (hasSchemaAnnotation(p.schema())) { Schema schema = processSchema(p.schema()); - - // TODO: merge??? if (schema != null) { parameter.setSchema(schema); } @@ -79,17 +77,17 @@ public static Parameter applyAnnotations(OpenAPI swagger, Parameter parameter, T } } else if (annotation.annotationType().getName().equals("javax.validation.constraints.Size")) { try { - if(parameter.getSchema() == null) { + if (parameter.getSchema() == null) { parameter.setSchema(new ArraySchema()); } - if(parameter.getSchema() instanceof ArraySchema) { + if (parameter.getSchema() instanceof ArraySchema) { ArraySchema as = (ArraySchema) parameter.getSchema(); Integer min = (Integer) annotation.annotationType().getMethod("min").invoke(annotation); - if(min != null) { + if (min != null) { as.setMinItems(min); } Integer max = (Integer) annotation.annotationType().getMethod("max").invoke(annotation); - if(max != null) { + if (max != null) { as.setMaxItems(max); } } @@ -99,9 +97,9 @@ public static Parameter applyAnnotations(OpenAPI swagger, Parameter parameter, T } } } - if(type != null) { + if (type != null) { Schema filled = fillSchema(parameter.getSchema(), type); - if(filled != null) { + if (filled != null) { parameter.setSchema(filled); } } @@ -109,15 +107,14 @@ public static Parameter applyAnnotations(OpenAPI swagger, Parameter parameter, T Schema paramSchema = parameter.getSchema(); - if(paramSchema != null) { - if(paramSchema instanceof ArraySchema) { + if (paramSchema != null) { + if (paramSchema instanceof ArraySchema) { ArraySchema as = (ArraySchema) paramSchema; - if(defaultValue != null) { + if (defaultValue != null) { as.getItems().setDefault(defaultValue); } - } - else { - if(defaultValue != null) { + } else { + if (defaultValue != null) { paramSchema.setDefault(defaultValue); } } @@ -286,33 +283,29 @@ public static Parameter applyAnnotations(OpenAPI swagger, Parameter parameter, T } public static Schema fillSchema(Schema schema, Type type) { - if(schema != null) { - if(schema != null && StringUtils.isBlank(schema.getType())) { + if (schema != null) { + if (schema != null && StringUtils.isBlank(schema.getType())) { PrimitiveType pt = PrimitiveType.fromType(type); - if(pt != null) { + if (pt != null) { Schema inner = pt.createProperty(); return merge(schema, inner); - } - else { + } else { return ModelConverters.getInstance().resolveProperty(type); } - } - else if("array".equals(schema.getType())) { - Schema inner = fillSchema(((ArraySchema)schema).getItems(), type); + } else if ("array".equals(schema.getType())) { + Schema inner = fillSchema(((ArraySchema) schema).getItems(), type); ArraySchema as = (ArraySchema) schema; as.setItems(inner); as.setMinItems(schema.getMinItems()); as.setMaxItems(schema.getMaxItems()); return as; } - } - else { + } else { PrimitiveType pt = PrimitiveType.fromType(type); - if(pt != null) { + if (pt != null) { Schema inner = pt.createProperty(); return merge(schema, inner); - } - else { + } else { return ModelConverters.getInstance().resolveProperty(type); } } @@ -321,46 +314,46 @@ else if("array".equals(schema.getType())) { // TODO! public static Schema merge(Schema from, Schema to) { - if(from == null) { + if (from == null) { return to; } - if(to.getDescription() == null) { + if (to.getDescription() == null) { to.setDescription(from.getDescription()); } - if(to.getDefault() == null) { + if (to.getDefault() == null) { to.setDefault(from.getDefault()); } - if(to.getEnum() == null) { + if (to.getEnum() == null) { to.setEnum(from.getEnum()); } - if(to.getExclusiveMinimum() == null) { + if (to.getExclusiveMinimum() == null) { to.setExclusiveMinimum(from.getExclusiveMinimum()); } - if(to.getExclusiveMaximum() == null) { + if (to.getExclusiveMaximum() == null) { to.setExclusiveMaximum(from.getExclusiveMaximum()); } - if(to.getMinimum() == null) { + if (to.getMinimum() == null) { to.setMinimum(from.getMinimum()); } - if(to.getMaximum() == null) { + if (to.getMaximum() == null) { to.setMaximum(from.getMaximum()); } return to; } private static boolean hasArrayAnnotation(io.swagger.oas.annotations.media.ArraySchema array) { - if(array.uniqueItems() == false + if (array.uniqueItems() == false && array.maxItems() == Integer.MIN_VALUE && array.minItems() == Integer.MAX_VALUE && !hasSchemaAnnotation(array.schema()) - ) { + ) { return false; } return true; } private static boolean hasSchemaAnnotation(io.swagger.oas.annotations.media.Schema schema) { - if(StringUtils.isBlank(schema.type()) + if (StringUtils.isBlank(schema.type()) && StringUtils.isBlank(schema.format()) && StringUtils.isBlank(schema.title()) && StringUtils.isBlank(schema.description()) @@ -389,7 +382,7 @@ private static boolean hasSchemaAnnotation(io.swagger.oas.annotations.media.Sche && schema.not().equals(Void.class) && schema.oneOf().length == 1 && schema.oneOf()[0].equals(Void.class) && schema.anyOf().length == 1 && schema.anyOf()[0].equals(Void.class) - ) { + ) { return false; } return true; @@ -407,72 +400,64 @@ private static Schema processArraySchema(io.swagger.oas.annotations.media.ArrayS private static Schema processSchema(io.swagger.oas.annotations.media.Schema schema) { Schema output = null; - if(schema.type() != null) { - if("integer".equals(schema.type())) { + if (schema.type() != null) { + if ("integer".equals(schema.type())) { output = new IntegerSchema(); - if(StringUtils.isNotBlank(schema.format())) { + if (StringUtils.isNotBlank(schema.format())) { output.format(schema.format()); } } - if("string".equals(schema.type())) { - if("password".equals(schema.format())) { + if ("string".equals(schema.type())) { + if ("password".equals(schema.format())) { output = new PasswordSchema(); - } - else if("binary".equals(schema.format())) { + } else if ("binary".equals(schema.format())) { output = new BinarySchema(); - } - else if("byte".equals(schema.format())) { + } else if ("byte".equals(schema.format())) { output = new ByteArraySchema(); - } - else if("date".equals(schema.format())) { + } else if ("date".equals(schema.format())) { output = new DateSchema(); - } - else if("date-time".equals(schema.format())) { + } else if ("date-time".equals(schema.format())) { output = new DateTimeSchema(); - } - else if("email".equals(schema.format())) { + } else if ("email".equals(schema.format())) { output = new EmailSchema(); - } - else if("uuid".equals(schema.format())) { + } else if ("uuid".equals(schema.format())) { output = new UUIDSchema(); - } - else { + } else { output = new StringSchema(); } - } - else { + } else { output = new Schema(); } // TODO: other types } - if(output != null) { - if(StringUtils.isNotBlank(schema._default())) { + if (output != null) { + if (StringUtils.isNotBlank(schema._default())) { output.setDefault(schema._default()); } - if(schema._enum() != null) { - for(String v : schema._enum()) { - if(StringUtils.isNotBlank(v)) { + if (schema._enum() != null) { + for (String v : schema._enum()) { + if (StringUtils.isNotBlank(v)) { output.addEnumItemObject(v); } } } - if(schema.exclusiveMinimum()) { + if (schema.exclusiveMinimum()) { output.exclusiveMinimum(true); } - if(schema.exclusiveMaximum()) { + if (schema.exclusiveMaximum()) { output.exclusiveMaximum(true); } - if(StringUtils.isNotBlank(schema.minimum())) { + if (StringUtils.isNotBlank(schema.minimum())) { output.minimum(new BigDecimal(schema.minimum())); } - if(StringUtils.isNotBlank(schema.maximum())) { + if (StringUtils.isNotBlank(schema.maximum())) { output.maximum(new BigDecimal(schema.maximum())); } - if(schema.minProperties() > 0) { + if (schema.minProperties() > 0) { output.minProperties(schema.minProperties()); } - if(schema.maxProperties() > 0) { + if (schema.maxProperties() > 0) { output.maxProperties(schema.maxProperties()); } } @@ -536,9 +521,9 @@ public interface ParamWrapper { * accessing supported parameter annotations. */ private static class AnnotationsHelper { -// private static final ApiParam DEFAULT_API_PARAM = getDefaultApiParam(null); + // private static final ApiParam DEFAULT_API_PARAM = getDefaultApiParam(null); private boolean context; -// private ParamWrapper apiParam = new ApiParamWrapper(DEFAULT_API_PARAM); + // private ParamWrapper apiParam = new ApiParamWrapper(DEFAULT_API_PARAM); private String type; private String format; private String defaultValue; @@ -563,7 +548,7 @@ private static class AnnotationsHelper { public AnnotationsHelper(List annotations, Type _type) { String rsDefault = null; Size size = null; - if(annotations != null) { + if (annotations != null) { for (Annotation item : annotations) { if ("javax.ws.rs.core.Context".equals(item.annotationType().getName())) { context = true; diff --git a/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java b/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java index 54fa01db0e..87f48e18f8 100644 --- a/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java +++ b/modules/swagger-core/src/main/java/io/swagger/util/ReflectionUtils.java @@ -258,7 +258,7 @@ public static Annotation[][] getParameterAnnotations(Method method) { .getParameterAnnotations(); for (int i = 0; i < methodAnnotations.length; i++) { - List types = new ArrayList(); + List types = new ArrayList<>(); for (int j = 0; j < methodAnnotations[i].length; j++) { types.add(methodAnnotations[i][j].annotationType()); } diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/DefaultParameterExtension.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/DefaultParameterExtension.java index f4386e3148..bd3d80af0f 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/DefaultParameterExtension.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/DefaultParameterExtension.java @@ -41,7 +41,7 @@ public class DefaultParameterExtension extends AbstractOpenAPIExtension { @Override public List extractParameters(List annotations, Type type, Set typesToSkip, Iterator chain) { if (shouldIgnoreType(type, typesToSkip)) { - return new ArrayList(); + return new ArrayList<>(); } List parameters = new ArrayList(); diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/OperationParser.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/OperationParser.java index 20cf970612..0aa20877b1 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/OperationParser.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/OperationParser.java @@ -1,6 +1,6 @@ package io.swagger.jaxrs2; -import io.swagger.jaxrs2.util.ReaderUtils; +import io.swagger.converter.ModelConverters; import io.swagger.oas.annotations.media.ExampleObject; import io.swagger.oas.models.ExternalDocumentation; import io.swagger.oas.models.examples.Example; @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; @@ -31,220 +32,200 @@ */ public class OperationParser { - public static Optional> getParametersList(io.swagger.oas.annotations.Parameter[] parameters) { - if (parameters == null) { - return Optional.empty(); - } - List parametersObject = new ArrayList<>(); - for (io.swagger.oas.annotations.Parameter parameter : parameters) { - Parameter parameterObject = new Parameter(); - parameterObject.setDescription(parameter.description()); - parameterObject.setDeprecated(parameter.deprecated()); - parameterObject.setName(parameter.name()); - parameterObject.setRequired(parameter.required()); - parameterObject.setStyle(StringUtils.isNoneBlank(parameter.style()) ? Parameter.StyleEnum.valueOf(parameter.style()) : null); - parameterObject.setAllowEmptyValue(parameter.allowEmptyValue()); - parameterObject.setAllowReserved(parameter.allowReserved()); - parameterObject.setExplode(parameter.explode()); - parameterObject.setIn(parameter.in()); - parameterObject.setContent(getContents(parameter.content()).get()); - - io.swagger.oas.annotations.media.Schema schema = parameter.schema(); - parameterObject.setSchema(getSchema(schema).get()); - parametersObject.add(parameterObject); - - } - return Optional.of(parametersObject); - } - - public static Optional getSchema(io.swagger.oas.annotations.media.Schema schema) { - if (schema == null) { - return Optional.empty(); - } - Schema schemaObject = new Schema(); - - schemaObject.set$ref(schema.ref()); - schemaObject.setDefault(schema._default()); - schemaObject.setDeprecated(schema.deprecated()); - schemaObject.setDescription(schema.description()); - ReaderUtils.getStringListFromStringArray(schema._enum()).ifPresent(schemas -> schemaObject.setEnum(schemas)); - schemaObject.setExample(schema.example()); - schemaObject.setExclusiveMaximum(schema.exclusiveMaximum()); - schemaObject.setExclusiveMinimum(schema.exclusiveMinimum()); - getExternalDocumentation(schema.externalDocs()).ifPresent(externalDocumentation -> schemaObject.setExternalDocs(externalDocumentation)); - schemaObject.setFormat(schema.format()); - schemaObject.setPattern(schema.pattern()); - schemaObject.setMaxLength(schema.maxLength()); - schemaObject.setMaxProperties(schema.maxProperties()); - schemaObject.setMinLength(schema.minLength()); - schemaObject.setMinProperties(schema.minProperties()); - schemaObject.setReadOnly(schema.readOnly()); - schemaObject.setType(schema.type()); - schemaObject.setTitle(schema.title()); - schemaObject.setWriteOnly(schema.writeOnly()); - - return Optional.of(schemaObject); - } - - public static Optional> getTags(String[] tags) { - if (tags == null) { - return Optional.empty(); - } - Set tagsList = new LinkedHashSet<>(); - for (String tag : tags) { - Tag tagObject = new Tag(); - tagObject.setDescription(tag); - tagObject.setName(tag); - tagsList.add(tagObject); - } - return Optional.of(tagsList); - } - - public static Optional> getServers(io.swagger.oas.annotations.servers.Server[] servers) { - if (servers == null) { - return Optional.empty(); - } - List serverObjects = new ArrayList<>(); - - for (io.swagger.oas.annotations.servers.Server server : servers) { - getServer(server).ifPresent(serverObject -> serverObjects.add(serverObject)); - } - return Optional.of(serverObjects); - } - - public static Optional getServer(io.swagger.oas.annotations.servers.Server server) { - if (server == null) { - return Optional.empty(); - } - - Server serverObject = new Server(); - serverObject.setUrl(server.url()); - serverObject.setDescription(server.description()); - io.swagger.oas.annotations.servers.ServerVariable[] serverVariables = server.variables(); - ServerVariables serverVariablesObject = new ServerVariables(); - for (io.swagger.oas.annotations.servers.ServerVariable serverVariable : serverVariables) { - ServerVariable serverVariableObject = new ServerVariable(); - serverVariableObject.setDescription(serverVariable.description()); - serverVariablesObject.addServerVariable(serverVariable.name(), serverVariableObject); - } - serverObject.setVariables(serverVariablesObject); - - return Optional.of(serverObject); - } - - public static Optional getExternalDocumentation(io.swagger.oas.annotations.ExternalDocumentation externalDocumentation) { - if (externalDocumentation == null) { - return Optional.empty(); - } - ExternalDocumentation external = new ExternalDocumentation(); - external.setDescription(externalDocumentation.description()); - external.setUrl(externalDocumentation.url()); - return Optional.of(external); - } - - public static Optional getRequestBody(io.swagger.oas.annotations.parameters.RequestBody requestBody) { - if (requestBody == null) { - return Optional.empty(); - } - RequestBody requestBodyObject = new RequestBody(); - requestBodyObject.setDescription(requestBody.description()); - requestBodyObject.setRequired(requestBody.required()); - getContents(requestBody.content()).ifPresent(content -> requestBodyObject.setContent(content)); - return Optional.of(requestBodyObject); - } - - public static Optional getApiResponses(final io.swagger.oas.annotations.responses.ApiResponse[] responses, io.swagger.oas.annotations.links.Link links) { - if (responses == null) { - return Optional.empty(); - } - ApiResponses apiResponsesObject = new ApiResponses(); - for (io.swagger.oas.annotations.responses.ApiResponse response : responses) { - ApiResponse apiResponseObject = new ApiResponse(); - Content content = getContent(response.content()).get(); - apiResponseObject.content(content); - apiResponseObject.setDescription(response.description()); - - apiResponsesObject.addApiResponse(response.responseCode(), apiResponseObject); - } - return Optional.of(apiResponsesObject); - } - - public static Optional getContents(io.swagger.oas.annotations.media.Content[] contents) { - if (contents == null) { - return Optional.empty(); - } - Content contentObject = new Content(); - for (io.swagger.oas.annotations.media.Content content : contents) { - ExampleObject[] examples = content.examples(); - for (ExampleObject example : examples) { - getMediaType(example).ifPresent(mediaType -> contentObject.addMediaType(content.mediaType(), mediaType)); - } - } - return Optional.of(contentObject); - } - - public static Optional getContent(io.swagger.oas.annotations.media.Content annotationContent) { - if (annotationContent == null) { - Optional.empty(); - } - Content content = new Content(); - if (annotationContent != null) { - ExampleObject[] examples = annotationContent.examples(); - for (ExampleObject example : examples) { - getMediaType(example).ifPresent(mediaType -> content.addMediaType(annotationContent.mediaType(), mediaType)); - } - } - return Optional.of(content); - } - - public static Optional getMediaType(ExampleObject example) { - if (example == null) { - return Optional.empty(); - } - MediaType mediaType = new MediaType(); - Example exampleObject = new Example(); - exampleObject.setDescription(example.name()); - exampleObject.setSummary(example.summary()); - exampleObject.setExternalValue(example.externalValue()); - exampleObject.setValue(example.value()); - mediaType.addExamples(example.name(), exampleObject); - return Optional.of(mediaType); - } - - public static Optional getInfo(io.swagger.oas.annotations.info.Info info) { - if (info == null) { - return Optional.empty(); - } - Info infoObject = new Info(); - infoObject.setDescription(info.description()); - infoObject.setTermsOfService(info.termsOfService()); - infoObject.setTitle(info.title()); - infoObject.setVersion(info.version()); - getContact(info.contact()).ifPresent(contact -> infoObject.setContact(contact)); - getLicense(info.license()).ifPresent(license -> infoObject.setLicense(license)); - - return Optional.of(infoObject); - } - - public static Optional getContact(io.swagger.oas.annotations.info.Contact contact) { - if (contact == null) { - return Optional.empty(); - } - Contact contactObject = new Contact(); - contactObject.setEmail(contact.email()); - contactObject.setName(contact.name()); - contactObject.setUrl(contact.url()); - return Optional.of(contactObject); - } - - public static Optional getLicense(io.swagger.oas.annotations.info.License license) { - if (license == null) { - return Optional.empty(); - } - License licenseObject = new License(); - licenseObject.setName(license.name()); - licenseObject.setUrl(license.url()); - - return Optional.of(licenseObject); - } + public static Optional> getParametersList(io.swagger.oas.annotations.Parameter[] parameters) { + if (parameters == null) { + return Optional.empty(); + } + List parametersObject = new ArrayList<>(); + for (io.swagger.oas.annotations.Parameter parameter : parameters) { + Parameter parameterObject = new Parameter(); + parameterObject.setDescription(parameter.description()); + parameterObject.setDeprecated(parameter.deprecated()); + parameterObject.setName(parameter.name()); + parameterObject.setRequired(parameter.required()); + parameterObject.setStyle(StringUtils.isNoneBlank(parameter.style()) ? Parameter.StyleEnum.valueOf(parameter.style()) : null); + parameterObject.setAllowEmptyValue(parameter.allowEmptyValue()); + parameterObject.setAllowReserved(parameter.allowReserved()); + parameterObject.setExplode(parameter.explode()); + parameterObject.setIn(parameter.in()); + parameterObject.setContent(getContents(parameter.content()).get()); + + parametersObject.add(parameterObject); + + } + return Optional.of(parametersObject); + } + + public static Optional> getSchema(io.swagger.oas.annotations.media.Schema schema) { + if (schema == null) { + return Optional.empty(); + } + if(schema.implementation() != Void.class){ + return Optional.of(ModelConverters.getInstance().readAll(schema.implementation())); + } + return Optional.empty(); + } + + public static Optional> getTags(String[] tags) { + if (tags == null) { + return Optional.empty(); + } + Set tagsList = new LinkedHashSet<>(); + for (String tag : tags) { + Tag tagObject = new Tag(); + tagObject.setDescription(tag); + tagObject.setName(tag); + tagsList.add(tagObject); + } + return Optional.of(tagsList); + } + + public static Optional> getServers(io.swagger.oas.annotations.servers.Server[] servers) { + if (servers == null) { + return Optional.empty(); + } + List serverObjects = new ArrayList<>(); + + for (io.swagger.oas.annotations.servers.Server server : servers) { + getServer(server).ifPresent(serverObject -> serverObjects.add(serverObject)); + } + return Optional.of(serverObjects); + } + + public static Optional getServer(io.swagger.oas.annotations.servers.Server server) { + if (server == null) { + return Optional.empty(); + } + + Server serverObject = new Server(); + serverObject.setUrl(server.url()); + serverObject.setDescription(server.description()); + io.swagger.oas.annotations.servers.ServerVariable[] serverVariables = server.variables(); + ServerVariables serverVariablesObject = new ServerVariables(); + for (io.swagger.oas.annotations.servers.ServerVariable serverVariable : serverVariables) { + ServerVariable serverVariableObject = new ServerVariable(); + serverVariableObject.setDescription(serverVariable.description()); + serverVariablesObject.addServerVariable(serverVariable.name(), serverVariableObject); + } + serverObject.setVariables(serverVariablesObject); + + return Optional.of(serverObject); + } + + public static Optional getExternalDocumentation(io.swagger.oas.annotations.ExternalDocumentation externalDocumentation) { + if (externalDocumentation == null) { + return Optional.empty(); + } + ExternalDocumentation external = new ExternalDocumentation(); + external.setDescription(externalDocumentation.description()); + external.setUrl(externalDocumentation.url()); + return Optional.of(external); + } + + public static Optional getRequestBody(io.swagger.oas.annotations.parameters.RequestBody requestBody) { + if (requestBody == null) { + return Optional.empty(); + } + RequestBody requestBodyObject = new RequestBody(); + requestBodyObject.setDescription(requestBody.description()); + requestBodyObject.setRequired(requestBody.required()); + getContents(requestBody.content()).ifPresent(content -> requestBodyObject.setContent(content)); + return Optional.of(requestBodyObject); + } + + public static Optional getApiResponses(final io.swagger.oas.annotations.responses.ApiResponse[] responses, io.swagger.oas.annotations.links.Link links) { + if (responses == null) { + return Optional.empty(); + } + ApiResponses apiResponsesObject = new ApiResponses(); + for (io.swagger.oas.annotations.responses.ApiResponse response : responses) { + ApiResponse apiResponseObject = new ApiResponse(); + Content content = getContent(response.content()).get(); + apiResponseObject.content(content); + apiResponseObject.setDescription(response.description()); + + apiResponsesObject.addApiResponse(response.responseCode(), apiResponseObject); + } + return Optional.of(apiResponsesObject); + } + + public static Optional getContents(io.swagger.oas.annotations.media.Content[] contents) { + if (contents == null) { + return Optional.empty(); + } + Content contentObject = new Content(); + for (io.swagger.oas.annotations.media.Content content : contents) { + ExampleObject[] examples = content.examples(); + for (ExampleObject example : examples) { + getMediaType(example).ifPresent(mediaType -> contentObject.addMediaType(content.mediaType(), mediaType)); + } + } + return Optional.of(contentObject); + } + + public static Optional getContent(io.swagger.oas.annotations.media.Content annotationContent) { + if (annotationContent == null) { + Optional.empty(); + } + Content content = new Content(); + // TODO - Add the Schema from the Content annotation an use the ModelConverter + if (annotationContent != null) { + ExampleObject[] examples = annotationContent.examples(); + for (ExampleObject example : examples) { + getMediaType(example).ifPresent(mediaType -> content.addMediaType(annotationContent.mediaType(), mediaType)); + } + } + return Optional.of(content); + } + + public static Optional getMediaType(ExampleObject example) { + if (example == null) { + return Optional.empty(); + } + MediaType mediaType = new MediaType(); + Example exampleObject = new Example(); + exampleObject.setDescription(example.name()); + exampleObject.setSummary(example.summary()); + exampleObject.setExternalValue(example.externalValue()); + exampleObject.setValue(example.value()); + mediaType.addExamples(example.name(), exampleObject); + return Optional.of(mediaType); + } + + public static Optional getInfo(io.swagger.oas.annotations.info.Info info) { + if (info == null) { + return Optional.empty(); + } + Info infoObject = new Info(); + infoObject.setDescription(info.description()); + infoObject.setTermsOfService(info.termsOfService()); + infoObject.setTitle(info.title()); + infoObject.setVersion(info.version()); + getContact(info.contact()).ifPresent(contact -> infoObject.setContact(contact)); + getLicense(info.license()).ifPresent(license -> infoObject.setLicense(license)); + + return Optional.of(infoObject); + } + + public static Optional getContact(io.swagger.oas.annotations.info.Contact contact) { + if (contact == null) { + return Optional.empty(); + } + Contact contactObject = new Contact(); + contactObject.setEmail(contact.email()); + contactObject.setName(contact.name()); + contactObject.setUrl(contact.url()); + return Optional.of(contactObject); + } + + public static Optional getLicense(io.swagger.oas.annotations.info.License license) { + if (license == null) { + return Optional.empty(); + } + License licenseObject = new License(); + licenseObject.setName(license.name()); + licenseObject.setUrl(license.url()); + + return Optional.of(licenseObject); + } } diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/Reader.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/Reader.java index 94c5ac4f2c..27a4e20e98 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/Reader.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/Reader.java @@ -30,334 +30,388 @@ import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Type; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.TreeSet; public class Reader { - private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class); - - private final ReaderConfig config; - - private OpenAPI openAPI; - private Paths paths; - private Set openApiTags; - - private static final String GET_METHOD = "get"; - private static final String POST_METHOD = "post"; - private static final String PUT_METHOD = "put"; - private static final String DELETE_METHOD = "delete"; - private static final String PATCH_METHOD = "patch"; - private static final String TRACE_METHOD = "trace"; - private static final String HEAD_METHOD = "head"; - private static final String OPTIONS_METHOD = "options"; - - public Reader(OpenAPI openAPI, ReaderConfig config) { - this.openAPI = openAPI; - paths = new Paths(); - openApiTags = new LinkedHashSet<>(); - this.config = new DefaultReaderConfig(); - } - - public OpenAPI getOpenAPI() { - return openAPI; - } - - /** - * Scans a single class for Swagger annotations - does not invoke ReaderListeners - */ - public OpenAPI read(Class cls) { - return read(cls, ""); - } - - /** - * Scans a set of classes for both ReaderListeners and OpenAPI annotations. All found listeners will - * be instantiated before any of the classes are scanned for Swagger annotations - so they can be invoked - * accordingly. - * - * @param classes a set of classes to scan - * @return the generated OpenAPI definition - */ - public OpenAPI read(Set> classes) { - Set> sortedClasses = new TreeSet<>(new Comparator>() { - @Override - public int compare(Class class1, Class class2) { - if (class1.equals(class2)) { - return 0; - } else if (class1.isAssignableFrom(class2)) { - return -1; - } else if (class2.isAssignableFrom(class1)) { - return 1; - } - return class1.getName().compareTo(class2.getName()); - } - }); - sortedClasses.addAll(classes); - - for (Class cls : sortedClasses) { - read(cls, ""); - } - - return openAPI; - } - - public OpenAPI read(Class cls, String parentPath) { - io.swagger.oas.annotations.security.SecurityScheme apiSecurityScheme = ReflectionUtils.getAnnotation(cls, io.swagger.oas.annotations.security.SecurityScheme.class); - io.swagger.oas.annotations.ExternalDocumentation apiExternalDocs = ReflectionUtils.getAnnotation(cls, io.swagger.oas.annotations.ExternalDocumentation.class); - io.swagger.oas.annotations.info.Info apiInfo = ReflectionUtils.getAnnotation(cls, io.swagger.oas.annotations.info.Info.class); - - Optional securityScheme = SecurityParser.getSecurityScheme(apiSecurityScheme); - Components components = new Components(); - if (securityScheme.isPresent()) { - Map securitySchemeMap = new HashMap<>(); - securitySchemeMap.put(securityScheme.get().getName(), securityScheme.get()); - components.setSecuritySchemes(securitySchemeMap); - } - openAPI.setComponents(components); - final javax.ws.rs.Path apiPath = ReflectionUtils.getAnnotation(cls, javax.ws.rs.Path.class); - - JavaType classType = TypeFactory.defaultInstance().constructType(cls); - BeanDescription bd = new ObjectMapper().getSerializationConfig().introspect(classType); - - final List globalParameters = new ArrayList<>(); - - // look for constructor-level annotated properties - globalParameters.addAll(ReaderUtils.collectConstructorParameters(cls, openAPI)); - - // look for field-level annotated properties - globalParameters.addAll(ReaderUtils.collectFieldParameters(cls, openAPI)); - - Method methods[] = cls.getMethods(); - for (Method method : methods) { - AnnotatedMethod annotatedMethod = bd.findMethod(method.getName(), method.getParameterTypes()); - - if (ReflectionUtils.isOverriddenMethod(method, cls)) { - continue; - } - javax.ws.rs.Path methodPath = ReflectionUtils.getAnnotation(method, javax.ws.rs.Path.class); - - String operationPath = ReaderUtils.getPath(apiPath, methodPath, parentPath); - - Map regexMap = new LinkedHashMap<>(); - operationPath = PathUtils.parsePath(operationPath, regexMap); - if (operationPath != null) { - if (ReaderUtils.isIgnored(operationPath, config)) { - continue; - } - - Operation operation = parseMethod(method); - PathItem pathItemObject = new PathItem(); - pathItemObject.set$ref(operation.getOperationId()); - pathItemObject.setSummary(operation.getSummary()); - pathItemObject.setDescription(operation.getDescription()); - String httpMethod = ReaderUtils.extractOperationMethod(operation, method, OpenAPIExtensions.chain()); - setPathItemOperation(pathItemObject, httpMethod, operation); - - Annotation[][] paramAnnotations = ReflectionUtils.getParameterAnnotations(method); - if (annotatedMethod == null) { - Type[] genericParameterTypes = method.getGenericParameterTypes(); - for (int i = 0; i < genericParameterTypes.length; i++) { - final Type type = TypeFactory.defaultInstance().constructType(genericParameterTypes[i], cls); - List parameters = getParameters(type, Arrays.asList(paramAnnotations[i])); - - for (Parameter parameter : parameters) { - //operation.parameter(parameter); - - } - } - } else { - for (int i = 0; i < annotatedMethod.getParameterCount(); i++) { - AnnotatedParameter param = annotatedMethod.getParameter(i); - final Type type = TypeFactory.defaultInstance().constructType(param.getParameterType(), cls); - List parameters = getParameters(type, Arrays.asList(paramAnnotations[i])); - - for (Parameter parameter : parameters) { - //operation.parameter(parameter); - } - } - } - - paths.addPathItem(pathItemObject.get$ref(), pathItemObject); - openAPI.setPaths(paths); - } - } - - ArrayList tagList = new ArrayList<>(); - tagList.addAll(openApiTags); - openAPI.setTags(tagList); - - OperationParser.getExternalDocumentation(apiExternalDocs).ifPresent(externalDocumentation -> openAPI.setExternalDocs(externalDocumentation)); - OperationParser.getInfo(apiInfo).ifPresent(info -> openAPI.setInfo(info)); - - return openAPI; - } - - public Operation parseMethod(Method method) { - JavaType classType = TypeFactory.defaultInstance().constructType(method.getDeclaringClass()); - return parseMethod(classType.getClass(), method); - } - - private Operation parseMethod(Class cls, Method method) { - Operation operation = new Operation(); - io.swagger.oas.annotations.Operation apiOperation = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.Operation.class); - io.swagger.oas.annotations.callbacks.Callback apiCallback = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.callbacks.Callback.class); - io.swagger.oas.annotations.security.SecurityRequirement apiSecurity = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.security.SecurityRequirement.class); - io.swagger.oas.annotations.links.Link apiLinks = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.links.Link.class); - - if (apiOperation != null) { - getCallbacks(apiCallback).ifPresent(callbacks -> operation.setCallbacks(callbacks)); - SecurityParser.getSecurityRequirement(apiSecurity).ifPresent(securityRequirements -> operation.setSecurity(securityRequirements)); - OperationParser.getApiResponses(apiOperation.responses(), apiLinks).ifPresent(apiResponses -> operation.setResponses(apiResponses)); - setOperationObjectFromApiOperationAnnotation(operation, apiOperation); - } - return operation; - } - - private Optional getCallbacks(io.swagger.oas.annotations.callbacks.Callback apiCallback) { - if (apiCallback == null) { - return Optional.empty(); - } - Callbacks callbacksObject = new Callbacks(); - Callback callbackObject = new Callback(); - PathItem pathItemObject = new PathItem(); - - for (io.swagger.oas.annotations.Operation callbackOperation : apiCallback.operation()) { - Operation callbackNewOperation = new Operation(); - setOperationObjectFromApiOperationAnnotation(callbackNewOperation, callbackOperation); - setPathItemOperation(pathItemObject, callbackOperation.method(), callbackNewOperation); - } - pathItemObject.setDescription(apiCallback.name()); - pathItemObject.setSummary(apiCallback.name()); - - callbackObject.addPathItem(apiCallback.name(), pathItemObject); - callbacksObject.addCallback(apiCallback.name(), callbackObject); - - return Optional.of(callbacksObject); - } - - private void setPathItemOperation(PathItem pathItemObject, String method, Operation callbackNewOperation) { - switch (method) { - case POST_METHOD: - pathItemObject.post(callbackNewOperation); - break; - case GET_METHOD: - pathItemObject.get(callbackNewOperation); - break; - case DELETE_METHOD: - pathItemObject.delete(callbackNewOperation); - break; - case PUT_METHOD: - pathItemObject.put(callbackNewOperation); - break; - case PATCH_METHOD: - pathItemObject.patch(callbackNewOperation); - break; - case TRACE_METHOD: - pathItemObject.trace(callbackNewOperation); - break; - case HEAD_METHOD: - pathItemObject.head(callbackNewOperation); - break; - case OPTIONS_METHOD: - pathItemObject.options(callbackNewOperation); - break; - default: - // Do nothing here - break; - - } - } - - private void setOperationObjectFromApiOperationAnnotation(Operation operation, io.swagger.oas.annotations.Operation apiOperation) { - ReaderUtils.getStringListFromStringArray(apiOperation.tags()).ifPresent(tags -> operation.setTags(tags)); - OperationParser.getTags(apiOperation.tags()).ifPresent(tag -> openApiTags.addAll(tag)); - operation.setSummary(apiOperation.summary()); - operation.setDescription(apiOperation.description()); - OperationParser.getExternalDocumentation(apiOperation.externalDocs()).ifPresent(externalDocumentation -> operation.setExternalDocs(externalDocumentation)); - operation.setOperationId(getOperationId(apiOperation.operationId())); - OperationParser.getParametersList(apiOperation.parameters()).ifPresent(parameters -> operation.setParameters(parameters)); - OperationParser.getRequestBody(apiOperation.requestBody()).ifPresent(requestBody -> operation.setRequestBody(requestBody)); - operation.setDeprecated(apiOperation.deprecated()); - OperationParser.getServers(apiOperation.servers()).ifPresent(servers -> operation.setServers(servers)); - } - - protected String getOperationId(String operationId) { - boolean operationIdUsed = existOperationId(operationId); - String operationIdToFind = null; - int counter = 0; - while (operationIdUsed) { - operationIdToFind = String.format("%s_%d", operationId, ++counter); - operationIdUsed = existOperationId(operationIdToFind); - } - if (operationIdToFind != null) { - operationId = operationIdToFind; - } - return operationId; - } - - private boolean existOperationId(String operationId) { - if (openAPI == null) { - return false; - } - if (openAPI.getPaths() == null || openAPI.getPaths().isEmpty()) { - return false; - } - for (PathItem path : openAPI.getPaths().values()) { - String pathOperationId = extractOperationIdFromPathItem(path); - if (operationId.equalsIgnoreCase(pathOperationId)) { - return true; - } - - } - return false; - } - - private List getParameters(Type type, List annotations) { - final Iterator chain = OpenAPIExtensions.chain(); - if (!chain.hasNext()) { - return Collections.emptyList(); - } - LOGGER.debug("getParameters for {}", type); - Set typesToSkip = new HashSet<>(); - final OpenAPIExtension extension = chain.next(); - LOGGER.debug("trying extension {}", extension); - - final List parameters = extension.extractParameters(annotations, type, typesToSkip, chain); - if (!parameters.isEmpty()) { - final List processed = new ArrayList(parameters.size()); - for (Parameter parameter : parameters) { - if (ParameterProcessor.applyAnnotations(openAPI, parameter, type, annotations) != null) { - processed.add(parameter); - } - } - return processed; - } else { - LOGGER.debug("no parameter found, looking at body params"); - final List body = new ArrayList(); - if (!typesToSkip.contains(type)) { - Parameter param = ParameterProcessor.applyAnnotations(openAPI, null, type, annotations); - if (param != null) { - body.add(param); - } - } - return body; - } - } - - private String extractOperationIdFromPathItem(PathItem path) { - if (path.getGet() != null) { - return path.getGet().getOperationId(); - } else if (path.getPost() != null) { - return path.getPost().getOperationId(); - } else if (path.getPut() != null) { - return path.getPut().getOperationId(); - } else if (path.getDelete() != null) { - return path.getDelete().getOperationId(); - } else if (path.getOptions() != null) { - return path.getOptions().getOperationId(); - } else if (path.getHead() != null) { - return path.getHead().getOperationId(); - } else if (path.getPatch() != null) { - return path.getPatch().getOperationId(); - } - return ""; - } + private static final Logger LOGGER = LoggerFactory.getLogger(Reader.class); + + private final ReaderConfig config; + + private OpenAPI openAPI; + private Paths paths; + private Set openApiTags; + + private static final String GET_METHOD = "get"; + private static final String POST_METHOD = "post"; + private static final String PUT_METHOD = "put"; + private static final String DELETE_METHOD = "delete"; + private static final String PATCH_METHOD = "patch"; + private static final String TRACE_METHOD = "trace"; + private static final String HEAD_METHOD = "head"; + private static final String OPTIONS_METHOD = "options"; + + public Reader(OpenAPI openAPI, ReaderConfig config) { + this.openAPI = openAPI; + paths = new Paths(); + openApiTags = new LinkedHashSet<>(); + this.config = new DefaultReaderConfig(); + } + + public OpenAPI getOpenAPI() { + return openAPI; + } + + /** + * Scans a single class for Swagger annotations - does not invoke ReaderListeners + */ + public OpenAPI read(Class cls) { + return read(cls, ""); + } + + /** + * Scans a set of classes for both ReaderListeners and OpenAPI annotations. All found listeners will + * be instantiated before any of the classes are scanned for OpenAPI annotations - so they can be invoked + * accordingly. + * + * @param classes a set of classes to scan + * @return the generated OpenAPI definition + */ + public OpenAPI read(Set> classes) { + Set> sortedClasses = new TreeSet<>(new Comparator>() { + @Override + public int compare(Class class1, Class class2) { + if (class1.equals(class2)) { + return 0; + } else if (class1.isAssignableFrom(class2)) { + return -1; + } else if (class2.isAssignableFrom(class1)) { + return 1; + } + return class1.getName().compareTo(class2.getName()); + } + }); + sortedClasses.addAll(classes); + + for (Class cls : sortedClasses) { + read(cls, ""); + } + + return openAPI; + } + + public OpenAPI read(Class cls, String parentPath) { + io.swagger.oas.annotations.security.SecurityScheme apiSecurityScheme = ReflectionUtils.getAnnotation(cls, io.swagger.oas.annotations.security.SecurityScheme.class); + io.swagger.oas.annotations.ExternalDocumentation apiExternalDocs = ReflectionUtils.getAnnotation(cls, io.swagger.oas.annotations.ExternalDocumentation.class); + io.swagger.oas.annotations.info.Info apiInfo = ReflectionUtils.getAnnotation(cls, io.swagger.oas.annotations.info.Info.class); + io.swagger.oas.annotations.media.Schema apiSchema = ReflectionUtils.getAnnotation(cls, io.swagger.oas.annotations.media.Schema.class); + + Optional securityScheme = SecurityParser.getSecurityScheme(apiSecurityScheme); + Components components = new Components(); + if (securityScheme.isPresent()) { + Map securitySchemeMap = new HashMap<>(); + securitySchemeMap.put(securityScheme.get().getName(), securityScheme.get()); + components.setSecuritySchemes(securitySchemeMap); + } + + OperationParser.getSchema(apiSchema).ifPresent(stringSchemaMap -> components.setSchemas(stringSchemaMap)); + + mergeComponents(openAPI, components); + + final javax.ws.rs.Path apiPath = ReflectionUtils.getAnnotation(cls, javax.ws.rs.Path.class); + + JavaType classType = TypeFactory.defaultInstance().constructType(cls); + BeanDescription bd = new ObjectMapper().getSerializationConfig().introspect(classType); + + final List globalParameters = new ArrayList<>(); + + // look for constructor-level annotated properties + globalParameters.addAll(ReaderUtils.collectConstructorParameters(cls, openAPI)); + + // look for field-level annotated properties + globalParameters.addAll(ReaderUtils.collectFieldParameters(cls, openAPI)); + + Method methods[] = cls.getMethods(); + for (Method method : methods) { + AnnotatedMethod annotatedMethod = bd.findMethod(method.getName(), method.getParameterTypes()); + + if (ReflectionUtils.isOverriddenMethod(method, cls)) { + continue; + } + javax.ws.rs.Path methodPath = ReflectionUtils.getAnnotation(method, javax.ws.rs.Path.class); + + String operationPath = ReaderUtils.getPath(apiPath, methodPath, parentPath); + + Map regexMap = new LinkedHashMap<>(); + operationPath = PathUtils.parsePath(operationPath, regexMap); + if (operationPath != null) { + if (ReaderUtils.isIgnored(operationPath, config)) { + continue; + } + + Operation operation = parseMethod(method); + PathItem pathItemObject = new PathItem(); + pathItemObject.set$ref(operation.getOperationId()); + pathItemObject.setSummary(operation.getSummary()); + pathItemObject.setDescription(operation.getDescription()); + String httpMethod = ReaderUtils.extractOperationMethod(operation, method, OpenAPIExtensions.chain()); + setPathItemOperation(pathItemObject, httpMethod, operation); + + Annotation[][] paramAnnotations = ReflectionUtils.getParameterAnnotations(method); + if (annotatedMethod == null) { + Type[] genericParameterTypes = method.getGenericParameterTypes(); + for (int i = 0; i < genericParameterTypes.length; i++) { + final Type type = TypeFactory.defaultInstance().constructType(genericParameterTypes[i], cls); + operation.setParameters(getParameters(type, Arrays.asList(paramAnnotations[i]))); + } + } else { + for (int i = 0; i < annotatedMethod.getParameterCount(); i++) { + AnnotatedParameter param = annotatedMethod.getParameter(i); + final Type type = TypeFactory.defaultInstance().constructType(param.getParameterType(), cls); + operation.setParameters(getParameters(type, Arrays.asList(paramAnnotations[i]))); + } + } + + paths.addPathItem(pathItemObject.get$ref(), pathItemObject); + if (openAPI.getPaths() != null) { + this.paths.putAll(openAPI.getPaths()); + } + + openAPI.setPaths(this.paths); + } + } + + ArrayList tagList = new ArrayList<>(); + tagList.addAll(openApiTags); + if (openAPI.getTags() != null) { + tagList.addAll(openAPI.getTags()); + } + openAPI.setTags(tagList); + + OperationParser.getExternalDocumentation(apiExternalDocs).ifPresent(externalDocumentation -> openAPI.setExternalDocs(externalDocumentation)); + OperationParser.getInfo(apiInfo).ifPresent(info -> openAPI.setInfo(info)); + + return openAPI; + } + + public Operation parseMethod(Method method) { + JavaType classType = TypeFactory.defaultInstance().constructType(method.getDeclaringClass()); + return parseMethod(classType.getClass(), method); + } + + private Operation parseMethod(Class cls, Method method) { + Operation operation = new Operation(); + io.swagger.oas.annotations.Operation apiOperation = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.Operation.class); + io.swagger.oas.annotations.callbacks.Callback apiCallback = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.callbacks.Callback.class); + io.swagger.oas.annotations.security.SecurityRequirement apiSecurity = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.security.SecurityRequirement.class); + io.swagger.oas.annotations.links.Link apiLinks = ReflectionUtils.getAnnotation(method, io.swagger.oas.annotations.links.Link.class); + + if (apiOperation != null) { + getCallbacks(apiCallback).ifPresent(callbacks -> operation.setCallbacks(callbacks)); + SecurityParser.getSecurityRequirement(apiSecurity).ifPresent(securityRequirements -> operation.setSecurity(securityRequirements)); + OperationParser.getApiResponses(apiOperation.responses(), apiLinks).ifPresent(apiResponses -> operation.setResponses(apiResponses)); + setOperationObjectFromApiOperationAnnotation(operation, apiOperation); + } + return operation; + } + + private Optional getCallbacks(io.swagger.oas.annotations.callbacks.Callback apiCallback) { + if (apiCallback == null) { + return Optional.empty(); + } + Callbacks callbacksObject = new Callbacks(); + Callback callbackObject = new Callback(); + PathItem pathItemObject = new PathItem(); + + for (io.swagger.oas.annotations.Operation callbackOperation : apiCallback.operation()) { + Operation callbackNewOperation = new Operation(); + setOperationObjectFromApiOperationAnnotation(callbackNewOperation, callbackOperation); + setPathItemOperation(pathItemObject, callbackOperation.method(), callbackNewOperation); + } + pathItemObject.setDescription(apiCallback.name()); + pathItemObject.setSummary(apiCallback.name()); + + callbackObject.addPathItem(apiCallback.name(), pathItemObject); + callbacksObject.addCallback(apiCallback.name(), callbackObject); + + return Optional.of(callbacksObject); + } + + private void setPathItemOperation(PathItem pathItemObject, String method, Operation callbackNewOperation) { + switch (method) { + case POST_METHOD: + pathItemObject.post(callbackNewOperation); + break; + case GET_METHOD: + pathItemObject.get(callbackNewOperation); + break; + case DELETE_METHOD: + pathItemObject.delete(callbackNewOperation); + break; + case PUT_METHOD: + pathItemObject.put(callbackNewOperation); + break; + case PATCH_METHOD: + pathItemObject.patch(callbackNewOperation); + break; + case TRACE_METHOD: + pathItemObject.trace(callbackNewOperation); + break; + case HEAD_METHOD: + pathItemObject.head(callbackNewOperation); + break; + case OPTIONS_METHOD: + pathItemObject.options(callbackNewOperation); + break; + default: + // Do nothing here + break; + } + } + + private void setOperationObjectFromApiOperationAnnotation(Operation operation, io.swagger.oas.annotations.Operation apiOperation) { + ReaderUtils.getStringListFromStringArray(apiOperation.tags()).ifPresent(tags -> operation.setTags(tags)); + OperationParser.getTags(apiOperation.tags()).ifPresent(tag -> openApiTags.addAll(tag)); + operation.setSummary(apiOperation.summary()); + operation.setDescription(apiOperation.description()); + OperationParser.getExternalDocumentation(apiOperation.externalDocs()).ifPresent(externalDocumentation -> operation.setExternalDocs(externalDocumentation)); + operation.setOperationId(getOperationId(apiOperation.operationId())); + OperationParser.getParametersList(apiOperation.parameters()).ifPresent(parameters -> operation.setParameters(parameters)); + OperationParser.getRequestBody(apiOperation.requestBody()).ifPresent(requestBody -> operation.setRequestBody(requestBody)); + operation.setDeprecated(apiOperation.deprecated()); + OperationParser.getServers(apiOperation.servers()).ifPresent(servers -> operation.setServers(servers)); + } + + protected String getOperationId(String operationId) { + boolean operationIdUsed = existOperationId(operationId); + String operationIdToFind = null; + int counter = 0; + while (operationIdUsed) { + operationIdToFind = String.format("%s_%d", operationId, ++counter); + operationIdUsed = existOperationId(operationIdToFind); + } + if (operationIdToFind != null) { + operationId = operationIdToFind; + } + return operationId; + } + + private boolean existOperationId(String operationId) { + if (openAPI == null) { + return false; + } + if (openAPI.getPaths() == null || openAPI.getPaths().isEmpty()) { + return false; + } + for (PathItem path : openAPI.getPaths().values()) { + String pathOperationId = extractOperationIdFromPathItem(path); + if (operationId.equalsIgnoreCase(pathOperationId)) { + return true; + } + + } + return false; + } + + private List getParameters(Type type, List annotations) { + final Iterator chain = OpenAPIExtensions.chain(); + if (!chain.hasNext()) { + return Collections.emptyList(); + } + LOGGER.debug("getParameters for {}", type); + Set typesToSkip = new HashSet<>(); + final OpenAPIExtension extension = chain.next(); + LOGGER.debug("trying extension {}", extension); + + final List parameters = extension.extractParameters(annotations, type, typesToSkip, chain); + if (!parameters.isEmpty()) { + final List processed = new ArrayList<>(parameters.size()); + for (Parameter parameter : parameters) { + if (ParameterProcessor.applyAnnotations(openAPI, parameter, type, annotations) != null) { + processed.add(parameter); + } + } + return processed; + } else { + LOGGER.debug("no parameter found, looking at body params"); + final List body = new ArrayList<>(); + if (!typesToSkip.contains(type)) { + Parameter param = ParameterProcessor.applyAnnotations(openAPI, null, type, annotations); + if (param != null) { + body.add(param); + } + } + return body; + } + } + + private void mergeComponents(OpenAPI openAPI, Components components) { + Components openAPIComponent = openAPI.getComponents(); + if (openAPIComponent != null && components != null) { + if (components.getCallbacks() != null) { + components.getCallbacks().putAll(openAPIComponent.getCallbacks()); + } + if (components.getExamples() != null) { + components.getExamples().putAll(openAPIComponent.getExamples()); + } + if (components.getExtensions() != null) { + components.getExtensions().putAll(openAPIComponent.getExtensions()); + } + if (components.getHeaders() != null) { + components.getHeaders().putAll(openAPIComponent.getHeaders()); + } + if (components.getLinks() != null) { + components.getLinks().putAll(openAPIComponent.getLinks()); + } + if (components.getParameters() != null) { + components.getParameters().putAll(openAPIComponent.getParameters()); + } + if (components.getRequestBodies() != null) { + components.getRequestBodies().putAll(openAPIComponent.getRequestBodies()); + } + if (components.getResponses() != null) { + components.getResponses().putAll(openAPIComponent.getResponses()); + } + if (components.getSchemas() != null) { + components.getSchemas().putAll(openAPIComponent.getSchemas()); + } + if (components.getSecuritySchemes() != null) { + components.getSecuritySchemes().putAll(openAPIComponent.getSecuritySchemes()); + } + openAPI.setComponents(components); + } else { + openAPI.setComponents(components); + } + } + + private String extractOperationIdFromPathItem(PathItem path) { + if (path.getGet() != null) { + return path.getGet().getOperationId(); + } else if (path.getPost() != null) { + return path.getPost().getOperationId(); + } else if (path.getPut() != null) { + return path.getPut().getOperationId(); + } else if (path.getDelete() != null) { + return path.getDelete().getOperationId(); + } else if (path.getOptions() != null) { + return path.getOptions().getOperationId(); + } else if (path.getHead() != null) { + return path.getHead().getOperationId(); + } else if (path.getPatch() != null) { + return path.getPatch().getOperationId(); + } + return ""; + } } \ No newline at end of file diff --git a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/ext/OpenAPIExtensions.java b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/ext/OpenAPIExtensions.java index 5661fb260a..3fa89e4645 100644 --- a/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/ext/OpenAPIExtensions.java +++ b/modules/swagger-jaxrs2/src/main/java/io/swagger/jaxrs2/ext/OpenAPIExtensions.java @@ -1,5 +1,6 @@ package io.swagger.jaxrs2.ext; +import io.swagger.jaxrs2.DefaultParameterExtension; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,12 +27,12 @@ public static Iterator chain() { } static { - extensions = new ArrayList(); + extensions = new ArrayList<>(); ServiceLoader loader = ServiceLoader.load(OpenAPIExtension.class); for (OpenAPIExtension ext : loader) { LOGGER.debug("adding extension " + ext); extensions.add(ext); } - //extensions.add(new DefaultParameterExtension()); + extensions.add(new DefaultParameterExtension()); } } \ No newline at end of file diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/ReaderTest.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/ReaderTest.java index 789d6f53c3..56af875a2a 100644 --- a/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/ReaderTest.java +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/ReaderTest.java @@ -1,331 +1,340 @@ package io.swagger.jaxrs2; import io.swagger.jaxrs2.resources.*; - -import io.swagger.oas.models.*; +import io.swagger.oas.models.Components; +import io.swagger.oas.models.ExternalDocumentation; +import io.swagger.oas.models.OpenAPI; +import io.swagger.oas.models.Operation; +import io.swagger.oas.models.PathItem; +import io.swagger.oas.models.Paths; import io.swagger.oas.models.callbacks.Callback; import io.swagger.oas.models.callbacks.Callbacks; -import io.swagger.oas.models.links.Link; -import io.swagger.oas.models.links.LinkParameters; import io.swagger.oas.models.media.Content; -import io.swagger.oas.models.media.Schema; import io.swagger.oas.models.parameters.Parameter; import io.swagger.oas.models.parameters.RequestBody; import io.swagger.oas.models.responses.ApiResponse; import io.swagger.oas.models.responses.ApiResponses; import io.swagger.oas.models.security.SecurityRequirement; -import org.testng.annotations.BeforeClass; +import io.swagger.oas.models.security.SecurityScheme; import org.testng.annotations.Test; -import javax.ws.rs.*; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HEAD; +import javax.ws.rs.OPTIONS; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import static org.testng.Assert.*; -import static org.testng.Assert.assertEquals; public class ReaderTest { - private static final String EXAMPLE_TAG = "Example Tag"; - private static final String SECOND_TAG = "Second Tag"; - private static final String OPERATION_SUMMARY = "Operation Summary"; - private static final String OPERATION_DESCRIPTION = "Operation Description"; - private static final String CALLBACK_POST_OPERATION_DESCRIPTION = "payload data will be sent"; - private static final String CALLBACK_GET_OPERATION_DESCRIPTION = "payload data will be received"; - private static final String APPLICATION_JSON = "application/json"; - private static final String RESPONSE_CODE_200 = "200"; - private static final String RESPONSE_CODE_DEFAULT = "default"; - private static final String RESPONSE_DESCRIPTION = "voila!"; - private static final String RESPONSE_DESCRIPTION_BOO = "boo"; - private static final String REQUEST_DESCRIPTION = "Request description"; - private static final String EXTERNAL_DOCS_DESCRIPTION = "External documentation description"; - private static final String EXTERNAL_DOCS_URL = "http://url.com"; - private static final String GENERIC_MEDIA_TYPE = "*/*"; - private static final String PARAMETER_IN = "path"; - private static final String PARAMETER_NAME = "subscriptionId"; - private static final String PARAMETER_DESCRIPTION = "parameter description"; - private static final String SCHEMA_TYPE = "string"; - private static final String SCHEMA_FORMAT = "uuid"; - private static final String SCHEMA_DESCRIPTION = "the generated UUID"; - private static final String CALLBACK_SUBSCRIPTION_ID = "subscription"; - private static final String SECURITY_KEY = "security_key"; - private static final String SCOPE_VALUE = "write:petsread:pets"; - private static final String LINK_DESCRIPTION = "Link Description"; - private static final String LINK_OPERATION_REF = "Operation Ref"; - private static final String LINK_OPERATION_ID = "Operation Id"; - private static final String OPERATION_ID = "operationId"; - - private static final int RESPONSES_NUMBER = 2; - private static final int TAG_NUMBER = 2; - private static final int CALLBACK_NUMBER = 1; - private static final int PARAMETER_NUMBER = 1; - private static final int SECURITY_REQUIREMENT_NUMBER = 1; - private static final int SCOPE_NUMBER = 1; - private static final int PATHS_NUMBER = 1; - - - @Test(description = "test a simple resource class") - public void testSimpleReadClass() { - Reader reader = new Reader(new OpenAPI(), null); - OpenAPI openAPI = reader.read(BasicFieldsResource.class); - Paths paths = openAPI.getPaths(); - assertEquals(PATHS_NUMBER, paths.size()); - PathItem pathItem = paths.get(OPERATION_ID); - assertNotNull(pathItem); - assertEquals(OPERATION_DESCRIPTION, pathItem.getDescription()); - assertEquals(OPERATION_SUMMARY, pathItem.getSummary()); - assertNull(pathItem.getPost()); - Operation operation = pathItem.getGet(); - assertNotNull(operation); - assertEquals(OPERATION_SUMMARY, operation.getSummary()); - assertEquals(OPERATION_DESCRIPTION, operation.getDescription()); - } - - @Test(description = "scan methods") - public void testCompleteReadClass() { - Reader reader = new Reader(new OpenAPI(), null); - OpenAPI openAPI = reader.read(CompleteFieldsResource.class); - Paths paths = openAPI.getPaths(); - assertEquals(PATHS_NUMBER, paths.size()); - PathItem pathItem = paths.get(OPERATION_ID); - assertNotNull(pathItem); - assertEquals(OPERATION_DESCRIPTION, pathItem.getDescription()); - assertEquals(OPERATION_SUMMARY, pathItem.getSummary()); - assertNull(pathItem.getPost()); - Operation operation = pathItem.getGet(); - assertNotNull(operation); - assertEquals(OPERATION_SUMMARY, operation.getSummary()); - assertEquals(OPERATION_DESCRIPTION, operation.getDescription()); - - assertEquals(TAG_NUMBER, operation.getTags().size()); - assertEquals(EXAMPLE_TAG, operation.getTags().get(0)); - assertEquals(SECOND_TAG, operation.getTags().get(1)); - - RequestBody requestBody = operation.getRequestBody(); - assertEquals(REQUEST_DESCRIPTION, requestBody.getDescription()); - - Content content = requestBody.getContent(); - assertNotNull(content); - assertNotNull(content.get(APPLICATION_JSON)); - - ExternalDocumentation externalDocs = operation.getExternalDocs(); - assertEquals(EXTERNAL_DOCS_DESCRIPTION, externalDocs.getDescription()); - assertEquals(EXTERNAL_DOCS_URL, externalDocs.getUrl()); - } - - - @Test(description = "scan methods") - public void testScanMethods() { - Reader reader = new Reader(new OpenAPI(), null); - Method[] methods = SimpleMethods.class.getMethods(); - for (final Method method : methods) { - if (isValidRestPath(method)) { - Operation operation = reader.parseMethod(method); - assertNotNull(operation); - } - } - } - - @Test(description = "Get a Summary and Description") - public void testGetSummaryAndDescription() { - Reader reader = new Reader(new OpenAPI(), null); - Method[] methods = BasicFieldsResource.class.getMethods(); - Operation operation = reader.parseMethod(methods[0]); - assertNotNull(operation); - assertEquals(OPERATION_SUMMARY, operation.getSummary()); - assertEquals(OPERATION_DESCRIPTION, operation.getDescription()); - } - - @Test(description = "Get the Param of an operation") - public void testSubscriptionIdParam() { - Reader reader = new Reader(new OpenAPI(), null); - OpenAPI openAPI = reader.read(DuplicatedOperationIdResource.class); - } - - @Test(description = "Do nothing") - public void testBasicEmptyOperation() { - Reader reader = new Reader(new OpenAPI(), null); - Method[] methods = BasicClass.class.getMethods(); - Operation operation = reader.parseMethod(methods[0]); - assertNull(operation.getCallbacks()); - assertNull(operation.getTags()); - assertNull(operation.getExternalDocs()); - assertNull(operation.getOperationId()); - assertNull(operation.getParameters()); - assertNull(operation.getResponses()); - assertNull(operation.getSecurity()); - assertNull(operation.getServers()); - assertNull(operation.getSummary()); - assertNull(operation.getDescription()); - } - - @Test(description = "Get a Duplicated Operation Id") - public void testResolveDuplicatedOperationId() { - Reader reader = new Reader(new OpenAPI(), null); - OpenAPI openAPI = reader.read(DuplicatedOperationIdResource.class); - - Paths paths = openAPI.getPaths(); - Operation firstOperation = paths.get("operationId").getGet(); - Operation secondOperation = paths.get("operationId_1").getGet(); - assertNotNull(firstOperation); - assertNotNull(secondOperation); - assertNotEquals(firstOperation.getOperationId(), secondOperation.getOperationId()); - } - - @Test(description = "Deprecated Method") - public void testDeprecatedMethod() { - Reader reader = new Reader(new OpenAPI(), null); - Method[] methods = DeprecatedFieldsResource.class.getMethods(); - Operation deprecatedOperation = reader.parseMethod(methods[0]); - assertNotNull(deprecatedOperation); - assertTrue(deprecatedOperation.getDeprecated()); - } - - @Test(description = "Get tags") - public void testGetTags() { - Reader reader = new Reader(new OpenAPI(), null); - Method[] methods = TagsResource.class.getMethods(); - Operation operation = reader.parseMethod(methods[0]); - assertNotNull(operation); - assertEquals(TAG_NUMBER, operation.getTags().size()); - assertEquals(EXAMPLE_TAG, operation.getTags().get(0)); - assertEquals(SECOND_TAG, operation.getTags().get(1)); - } - - @Test(description = "Responses") - public void testGetResponses() { - Reader reader = new Reader(new OpenAPI(), null); - - Method[] methods = ResponsesResource.class.getMethods(); - - Operation responseOperation = reader.parseMethod(methods[0]); - assertNotNull(responseOperation); - - ApiResponses responses = responseOperation.getResponses(); - assertEquals(RESPONSES_NUMBER, responses.size()); - - ApiResponse apiResponse = responses.get(RESPONSE_CODE_200); - assertNotNull(apiResponse); - assertEquals(RESPONSE_DESCRIPTION, apiResponse.getDescription()); - } - - @Test(description = "Request Body") - public void testGetRequestBody() { - Reader reader = new Reader(new OpenAPI(), null); - - Method[] methods = RequestBodyResource.class.getMethods(); - - Operation requestOperation = reader.parseMethod(methods[0]); - assertNotNull(requestOperation); - RequestBody requestBody = requestOperation.getRequestBody(); - assertEquals(REQUEST_DESCRIPTION, requestBody.getDescription()); - - Content content = requestBody.getContent(); - assertNotNull(content); - assertNotNull(content.get(APPLICATION_JSON)); - - } - - @Test(description = "External Docs") - public void testGetExternalDocs() { - Reader reader = new Reader(new OpenAPI(), null); - - Method[] methods = ExternalDocsReference.class.getMethods(); - Operation externalDocsOperation = reader.parseMethod(methods[0]); - assertNotNull(externalDocsOperation); - ExternalDocumentation externalDocs = externalDocsOperation.getExternalDocs(); - assertEquals(EXTERNAL_DOCS_DESCRIPTION, externalDocs.getDescription()); - assertEquals(EXTERNAL_DOCS_URL, externalDocs.getUrl()); - } - - @Test(description = "Parameters") - public void testGetParameters() { - Reader reader = new Reader(new OpenAPI(), null); - - Method[] methods = ParametersResource.class.getMethods(); - - Operation parametersOperation = reader.parseMethod(methods[0]); - assertNotNull(parametersOperation); - - List parameters = parametersOperation.getParameters(); - assertNotNull(parameters); - assertEquals(PARAMETER_NUMBER, parameters.size()); - Parameter parameter = parameters.get(0); - assertNotNull(parameter); - assertEquals(PARAMETER_IN, parameter.getIn()); - assertEquals(PARAMETER_NAME, parameter.getName()); - assertEquals(PARAMETER_DESCRIPTION, parameter.getDescription()); - assertEquals(Boolean.TRUE, parameter.getRequired()); - assertEquals(Boolean.TRUE, parameter.getAllowEmptyValue()); - assertEquals(Boolean.TRUE, parameter.getAllowReserved()); - assertEquals(Boolean.FALSE, parameter.getDeprecated()); - Schema schema = parameter.getSchema(); - assertNotNull(schema); - assertEquals(SCHEMA_TYPE, schema.getType()); - assertEquals(SCHEMA_FORMAT, schema.getFormat()); - assertEquals(SCHEMA_DESCRIPTION, schema.getDescription()); - assertEquals(Boolean.TRUE, schema.getReadOnly()); - } - - @Test(description = "Security Requirement") - public void testSecurityRequirement() { - Reader reader = new Reader(new OpenAPI(), null); - - Method[] methods = SecurityResource.class.getMethods(); - - Operation securityOperation = reader.parseMethod(methods[0]); - assertNotNull(securityOperation); - List securityRequirements = securityOperation.getSecurity(); - assertNotNull(securityRequirements); - assertEquals(SECURITY_REQUIREMENT_NUMBER, securityRequirements.size()); - List scopes = securityRequirements.get(0).get(SECURITY_KEY); - assertNotNull(scopes); - assertEquals(SCOPE_NUMBER, scopes.size()); - assertEquals(SCOPE_VALUE, scopes.get(0)); - } - - - @Test(description = "Callbacks") - public void testGetCallbacks() { - Reader reader = new Reader(new OpenAPI(), null); - - Method[] methods = SimpleCallbackResource.class.getMethods(); - Operation callbackOperation = reader.parseMethod(methods[0]); - assertNotNull(callbackOperation); - Callbacks callbacks = callbackOperation.getCallbacks(); - assertNotNull(callbacks); - Callback callback = callbacks.get(CALLBACK_SUBSCRIPTION_ID); - assertNotNull(callback); - PathItem pathItem = callback.get(CALLBACK_SUBSCRIPTION_ID); - assertNotNull(pathItem); - Operation postOperation = pathItem.getPost(); - assertNotNull(postOperation); - assertEquals(CALLBACK_POST_OPERATION_DESCRIPTION, postOperation.getDescription()); - - List parameters = postOperation.getParameters(); - assertNotNull(parameters); - assertEquals(CALLBACK_NUMBER, parameters.size()); - - Operation getOperation = pathItem.getGet(); - assertNotNull(getOperation); - assertEquals(CALLBACK_GET_OPERATION_DESCRIPTION, getOperation.getDescription()); - - Operation putOperation = pathItem.getPut(); - assertNotNull(putOperation); - assertEquals(CALLBACK_POST_OPERATION_DESCRIPTION, putOperation.getDescription()); - - } - - private Boolean isValidRestPath(Method method) { - for (Class item : Arrays.asList(GET.class, PUT.class, POST.class, DELETE.class, - OPTIONS.class, HEAD.class)) { - if (method.getAnnotation(item) != null) { - return true; - } - } - return false; - } + private static final String EXAMPLE_TAG = "Example Tag"; + private static final String SECOND_TAG = "Second Tag"; + private static final String OPERATION_SUMMARY = "Operation Summary"; + private static final String OPERATION_DESCRIPTION = "Operation Description"; + private static final String CALLBACK_POST_OPERATION_DESCRIPTION = "payload data will be sent"; + private static final String CALLBACK_GET_OPERATION_DESCRIPTION = "payload data will be received"; + private static final String APPLICATION_JSON = "application/json"; + private static final String RESPONSE_CODE_200 = "200"; + private static final String RESPONSE_DESCRIPTION = "voila!"; + private static final String REQUEST_DESCRIPTION = "Request description"; + private static final String EXTERNAL_DOCS_DESCRIPTION = "External documentation description"; + private static final String EXTERNAL_DOCS_URL = "http://url.com"; + private static final String PARAMETER_IN = "path"; + private static final String PARAMETER_NAME = "subscriptionId"; + private static final String PARAMETER_DESCRIPTION = "parameter description"; + private static final String CALLBACK_SUBSCRIPTION_ID = "subscription"; + private static final String SECURITY_KEY = "security_key"; + private static final String SCOPE_VALUE = "write:petsread:pets"; + private static final String OPERATION_ID = "operationId"; + + private static final int RESPONSES_NUMBER = 2; + private static final int TAG_NUMBER = 2; + private static final int SCHEMAS = 2; + private static final int CALLBACK_NUMBER = 1; + private static final int PARAMETER_NUMBER = 1; + private static final int SECURITY_REQUIREMENT_NUMBER = 1; + private static final int SCOPE_NUMBER = 1; + private static final int PATHS_NUMBER = 1; + + + @Test(description = "test a simple resource class") + public void testSimpleReadClass() { + Reader reader = new Reader(new OpenAPI(), null); + OpenAPI openAPI = reader.read(BasicFieldsResource.class); + Paths paths = openAPI.getPaths(); + assertEquals(PATHS_NUMBER, paths.size()); + PathItem pathItem = paths.get(OPERATION_ID); + assertNotNull(pathItem); + assertEquals(OPERATION_DESCRIPTION, pathItem.getDescription()); + assertEquals(OPERATION_SUMMARY, pathItem.getSummary()); + assertNull(pathItem.getPost()); + Operation operation = pathItem.getGet(); + assertNotNull(operation); + assertEquals(OPERATION_SUMMARY, operation.getSummary()); + assertEquals(OPERATION_DESCRIPTION, operation.getDescription()); + } + + @Test(description = "scan methods") + public void testCompleteReadClass() { + Reader reader = new Reader(new OpenAPI(), null); + OpenAPI openAPI = reader.read(CompleteFieldsResource.class); + Paths paths = openAPI.getPaths(); + assertEquals(PATHS_NUMBER, paths.size()); + PathItem pathItem = paths.get(OPERATION_ID); + assertNotNull(pathItem); + assertEquals(OPERATION_DESCRIPTION, pathItem.getDescription()); + assertEquals(OPERATION_SUMMARY, pathItem.getSummary()); + assertNull(pathItem.getPost()); + Operation operation = pathItem.getGet(); + assertNotNull(operation); + assertEquals(OPERATION_SUMMARY, operation.getSummary()); + assertEquals(OPERATION_DESCRIPTION, operation.getDescription()); + + assertEquals(TAG_NUMBER, operation.getTags().size()); + assertEquals(EXAMPLE_TAG, operation.getTags().get(0)); + assertEquals(SECOND_TAG, operation.getTags().get(1)); + + RequestBody requestBody = operation.getRequestBody(); + assertEquals(REQUEST_DESCRIPTION, requestBody.getDescription()); + + Content content = requestBody.getContent(); + assertNotNull(content); + assertNotNull(content.get(APPLICATION_JSON)); + + ExternalDocumentation externalDocs = operation.getExternalDocs(); + assertEquals(EXTERNAL_DOCS_DESCRIPTION, externalDocs.getDescription()); + assertEquals(EXTERNAL_DOCS_URL, externalDocs.getUrl()); + } + + + @Test(description = "scan methods") + public void testScanMethods() { + Reader reader = new Reader(new OpenAPI(), null); + Method[] methods = SimpleMethods.class.getMethods(); + for (final Method method : methods) { + if (isValidRestPath(method)) { + Operation operation = reader.parseMethod(method); + assertNotNull(operation); + } + } + } + + @Test(description = "Get a Summary and Description") + public void testGetSummaryAndDescription() { + Reader reader = new Reader(new OpenAPI(), null); + Method[] methods = BasicFieldsResource.class.getMethods(); + Operation operation = reader.parseMethod(methods[0]); + assertNotNull(operation); + assertEquals(OPERATION_SUMMARY, operation.getSummary()); + assertEquals(OPERATION_DESCRIPTION, operation.getDescription()); + } + + @Test(description = "Do nothing because there aren't Operation Annotations") + public void testBasicEmptyOperation() { + Reader reader = new Reader(new OpenAPI(), null); + Method[] methods = BasicClass.class.getMethods(); + Operation operation = reader.parseMethod(methods[0]); + assertNull(operation.getCallbacks()); + assertNull(operation.getTags()); + assertNull(operation.getExternalDocs()); + assertNull(operation.getOperationId()); + assertNull(operation.getParameters()); + assertNull(operation.getResponses()); + assertNull(operation.getSecurity()); + assertNull(operation.getServers()); + assertNull(operation.getSummary()); + assertNull(operation.getDescription()); + } + + @Test(description = "Get a Duplicated Operation Id") + public void testResolveDuplicatedOperationId() { + Reader reader = new Reader(new OpenAPI(), null); + OpenAPI openAPI = reader.read(DuplicatedOperationIdResource.class); + + Paths paths = openAPI.getPaths(); + Operation firstOperation = paths.get("operationId").getGet(); + Operation secondOperation = paths.get("operationId_1").getGet(); + assertNotNull(firstOperation); + assertNotNull(secondOperation); + assertNotEquals(firstOperation.getOperationId(), secondOperation.getOperationId()); + } + + @Test(description = "Test a Set of classes") + public void testSetOfClasses() { + Set> classes = new HashSet<>(); + classes.add(SecurityResource.class); + classes.add(DuplicatedSecurityResource.class); + + Reader reader = new Reader(new OpenAPI(), null); + OpenAPI openAPI = reader.read(classes); + assertNotNull(openAPI); + Components components = openAPI.getComponents(); + assertNotNull(components); + Map securitySchemes = components.getSecuritySchemes(); + assertNotNull(securitySchemes); + assertEquals(SCHEMAS, securitySchemes.size()); + } + + @Test(description = "Deprecated Method") + public void testDeprecatedMethod() { + Reader reader = new Reader(new OpenAPI(), null); + Method[] methods = DeprecatedFieldsResource.class.getMethods(); + Operation deprecatedOperation = reader.parseMethod(methods[0]); + assertNotNull(deprecatedOperation); + assertTrue(deprecatedOperation.getDeprecated()); + } + + @Test(description = "Get tags") + public void testGetTags() { + Reader reader = new Reader(new OpenAPI(), null); + Method[] methods = TagsResource.class.getMethods(); + Operation operation = reader.parseMethod(methods[0]); + assertNotNull(operation); + assertEquals(TAG_NUMBER, operation.getTags().size()); + assertEquals(EXAMPLE_TAG, operation.getTags().get(0)); + assertEquals(SECOND_TAG, operation.getTags().get(1)); + } + + @Test(description = "Responses") + public void testGetResponses() { + Reader reader = new Reader(new OpenAPI(), null); + + Method[] methods = ResponsesResource.class.getMethods(); + + Operation responseOperation = reader.parseMethod(methods[0]); + assertNotNull(responseOperation); + + ApiResponses responses = responseOperation.getResponses(); + assertEquals(RESPONSES_NUMBER, responses.size()); + + ApiResponse apiResponse = responses.get(RESPONSE_CODE_200); + assertNotNull(apiResponse); + assertEquals(RESPONSE_DESCRIPTION, apiResponse.getDescription()); + } + + @Test(description = "Request Body") + public void testGetRequestBody() { + Reader reader = new Reader(new OpenAPI(), null); + + Method[] methods = RequestBodyResource.class.getMethods(); + + Operation requestOperation = reader.parseMethod(methods[0]); + assertNotNull(requestOperation); + RequestBody requestBody = requestOperation.getRequestBody(); + assertEquals(REQUEST_DESCRIPTION, requestBody.getDescription()); + + Content content = requestBody.getContent(); + assertNotNull(content); + assertNotNull(content.get(APPLICATION_JSON)); + + } + + @Test(description = "External Docs") + public void testGetExternalDocs() { + Reader reader = new Reader(new OpenAPI(), null); + + Method[] methods = ExternalDocsReference.class.getMethods(); + Operation externalDocsOperation = reader.parseMethod(methods[0]); + assertNotNull(externalDocsOperation); + ExternalDocumentation externalDocs = externalDocsOperation.getExternalDocs(); + assertEquals(EXTERNAL_DOCS_DESCRIPTION, externalDocs.getDescription()); + assertEquals(EXTERNAL_DOCS_URL, externalDocs.getUrl()); + } + + @Test(description = "Parameters") + public void testGetParameters() { + Reader reader = new Reader(new OpenAPI(), null); + + Method[] methods = ParametersResource.class.getMethods(); + + Operation parametersOperation = reader.parseMethod(methods[0]); + assertNotNull(parametersOperation); + + List parameters = parametersOperation.getParameters(); + assertNotNull(parameters); + assertEquals(PARAMETER_NUMBER, parameters.size()); + Parameter parameter = parameters.get(0); + assertNotNull(parameter); + assertEquals(PARAMETER_IN, parameter.getIn()); + assertEquals(PARAMETER_NAME, parameter.getName()); + assertEquals(PARAMETER_DESCRIPTION, parameter.getDescription()); + assertEquals(Boolean.TRUE, parameter.getRequired()); + assertEquals(Boolean.TRUE, parameter.getAllowEmptyValue()); + assertEquals(Boolean.TRUE, parameter.getAllowReserved()); + assertEquals(Boolean.FALSE, parameter.getDeprecated()); + } + + @Test(description = "Security Requirement") + public void testSecurityRequirement() { + Reader reader = new Reader(new OpenAPI(), null); + + Method[] methods = SecurityResource.class.getMethods(); + + Operation securityOperation = reader.parseMethod(methods[0]); + assertNotNull(securityOperation); + List securityRequirements = securityOperation.getSecurity(); + assertNotNull(securityRequirements); + assertEquals(SECURITY_REQUIREMENT_NUMBER, securityRequirements.size()); + List scopes = securityRequirements.get(0).get(SECURITY_KEY); + assertNotNull(scopes); + assertEquals(SCOPE_NUMBER, scopes.size()); + assertEquals(SCOPE_VALUE, scopes.get(0)); + } + + + @Test(description = "Callbacks") + public void testGetCallbacks() { + Reader reader = new Reader(new OpenAPI(), null); + + Method[] methods = SimpleCallbackResource.class.getMethods(); + Operation callbackOperation = reader.parseMethod(methods[0]); + assertNotNull(callbackOperation); + Callbacks callbacks = callbackOperation.getCallbacks(); + assertNotNull(callbacks); + Callback callback = callbacks.get(CALLBACK_SUBSCRIPTION_ID); + assertNotNull(callback); + PathItem pathItem = callback.get(CALLBACK_SUBSCRIPTION_ID); + assertNotNull(pathItem); + Operation postOperation = pathItem.getPost(); + assertNotNull(postOperation); + assertEquals(CALLBACK_POST_OPERATION_DESCRIPTION, postOperation.getDescription()); + + List parameters = postOperation.getParameters(); + assertNotNull(parameters); + assertEquals(CALLBACK_NUMBER, parameters.size()); + + Operation getOperation = pathItem.getGet(); + assertNotNull(getOperation); + assertEquals(CALLBACK_GET_OPERATION_DESCRIPTION, getOperation.getDescription()); + + Operation putOperation = pathItem.getPut(); + assertNotNull(putOperation); + assertEquals(CALLBACK_POST_OPERATION_DESCRIPTION, putOperation.getDescription()); + } + + @Test(description = "Get the Param of an operation") + public void testSubscriptionIdParam() { + Reader reader = new Reader(new OpenAPI(), null); + OpenAPI openAPI = reader.read(BasicFieldsResource.class); + assertNotNull(openAPI); + } + + private Boolean isValidRestPath(Method method) { + for (Class item : Arrays.asList(GET.class, PUT.class, POST.class, DELETE.class, + OPTIONS.class, HEAD.class)) { + if (method.getAnnotation(item) != null) { + return true; + } + } + return false; + } } diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/BasicFieldsResource.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/BasicFieldsResource.java index 9d999e680e..626c0a4159 100644 --- a/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/BasicFieldsResource.java +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/BasicFieldsResource.java @@ -1,6 +1,7 @@ package io.swagger.jaxrs2.resources; import io.swagger.oas.annotations.Operation; +import io.swagger.oas.annotations.info.Info; import javax.ws.rs.GET; import javax.ws.rs.Path; diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/DuplicatedSecurityResource.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/DuplicatedSecurityResource.java new file mode 100644 index 0000000000..e8ec092338 --- /dev/null +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/jaxrs2/resources/DuplicatedSecurityResource.java @@ -0,0 +1,37 @@ +package io.swagger.jaxrs2.resources; + +import io.swagger.oas.annotations.Operation; +import io.swagger.oas.annotations.security.OAuthFlow; +import io.swagger.oas.annotations.security.OAuthFlows; +import io.swagger.oas.annotations.security.Scopes; +import io.swagger.oas.annotations.security.SecurityRequirement; +import io.swagger.oas.annotations.security.SecurityScheme; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +/** + * Created by RafaelLopez on 5/20/17. + */ +@SecurityScheme(name = "myOauth2Security2", + type = "oauth2", + in = "header", + description = "myOauthSecurity Description2", + flows = @OAuthFlows(implicit = @OAuthFlow(authorizationUrl = "http://x.com", + scopes = @Scopes( + name = "write:pets", + description = "modify pets in your account")) + ) +) +public class DuplicatedSecurityResource { + + @GET + @Path("/") + @Operation(operationId = "Operation Id", + description = "description") + @SecurityRequirement(name = "security_key", + scopes = {"write:pets", "read:pets"} + ) + public void getSecurity() { + } +} diff --git a/pom.xml b/pom.xml index 62492835cd..8f534f755e 100644 --- a/pom.xml +++ b/pom.xml @@ -82,31 +82,39 @@ target ${project.artifactId}-${project.version} + + maven-compiler-plugin + 3.6.1 + + 1.8 + 1.8 + + - - - - - + + + + + org.apache.maven.plugins maven-enforcer-plugin ${enforcer-plugin-version} - - enforce-versions - - enforce - - - - - - - + + enforce-versions + + enforce + + + + + + + - + maven-dependency-plugin @@ -141,7 +149,7 @@ 2.7 true - 1.7 + 1.8 UTF-8 1g @@ -159,14 +167,6 @@ - - maven-compiler-plugin - 3.0 - - 1.8 - 1.8 - - org.apache.maven.plugins maven-jar-plugin