This is an automated email from the ASF dual-hosted git repository. chanjarster pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/servicecomb-toolkit.git
commit dc85d20a22f17451e30a2f6780e39acee1203393 Author: kakulisen <[email protected]> AuthorDate: Sat Oct 26 09:01:21 2019 +0800 add oas-generator to generate openapi v3 Signed-off-by: kakulisen <[email protected]> --- oas-generator/oas-generator-core/pom.xml | 68 ++++++++ .../servicecomb/toolkit/generator/HttpStatus.java | 24 +++ .../toolkit/generator/MediaTypeConst.java | 54 ++++++ .../servicecomb/toolkit/generator/OasContext.java | 151 ++++++++++++++++ .../toolkit/generator/OasGenerator.java | 63 +++++++ .../toolkit/generator/OperationContext.java | 192 +++++++++++++++++++++ .../toolkit/generator/ParameterContext.java | 141 +++++++++++++++ .../generator/annotation/AnnotationProcessor.java | 22 +++ .../ApiResponseMethodAnnotationProcessor.java | 63 +++++++ .../ApiResponsesMethodAnnotationProcessor.java | 39 +++++ .../annotation/ClassAnnotationProcessor.java | 21 +++ .../annotation/MethodAnnotationProcessor.java | 21 +++ .../generator/annotation/ModelInterceptor.java | 28 +++ .../OperationMethodAnnotationProcessor.java | 57 ++++++ .../annotation/ParamAnnotationProcessor.java | 21 +++ .../annotation/ParameterAnnotationProcessor.java | 53 ++++++ .../generator/parser/AbstractAnnotationParser.java | 152 ++++++++++++++++ .../parser/api/OpenApiAnnotationParser.java | 57 ++++++ .../generator/util/ArrayModelConverter.java | 55 ++++++ .../generator/util/LocalVariableVisitor.java | 71 ++++++++ .../toolkit/generator/util/ModelConverter.java | 142 +++++++++++++++ .../toolkit/generator/util/ParamUtils.java | 122 +++++++++++++ .../toolkit/generator/AnnotationProcessorTest.java | 129 ++++++++++++++ .../toolkit/generator/OasGeneratorTest.java | 90 ++++++++++ .../servicecomb/toolkit/generator/ParserTest.java | 55 ++++++ .../servicecomb/toolkit/generator/UtilsTest.java | 83 +++++++++ oas-generator/pom.xml | 64 +++++++ 27 files changed, 2038 insertions(+) diff --git a/oas-generator/oas-generator-core/pom.xml b/oas-generator/oas-generator-core/pom.xml new file mode 100644 index 0000000..1a7a35c --- /dev/null +++ b/oas-generator/oas-generator-core/pom.xml @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>oas-generator</artifactId> + <groupId>org.apache.servicecomb.toolkit</groupId> + <version>0.2.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>oas-generator-core</artifactId> + + <properties> + <swagger.version>2.0.9</swagger.version> + </properties> + + <dependencies> + <dependency> + <groupId>io.swagger.core.v3</groupId> + <artifactId>swagger-models</artifactId> + <version>${swagger.version}</version> + </dependency> + + <dependency> + <groupId>io.swagger.core.v3</groupId> + <artifactId>swagger-annotations</artifactId> + <version>${swagger.version}</version> + </dependency> + + <dependency> + <groupId>io.swagger.core.v3</groupId> + <artifactId>swagger-core</artifactId> + <version>${swagger.version}</version> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + </dependency> + + <dependency> + <groupId>org.ow2.asm</groupId> + <artifactId>asm</artifactId> + <version>7.2</version> + </dependency> + + </dependencies> + + +</project> \ No newline at end of file diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/HttpStatus.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/HttpStatus.java new file mode 100644 index 0000000..00a12e3 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/HttpStatus.java @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +public class HttpStatus { + + public static String OK = "200"; + +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/MediaTypeConst.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/MediaTypeConst.java new file mode 100644 index 0000000..624e143 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/MediaTypeConst.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +/** + * Common media type constants + * + * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7">HTTP/1.1 section 3.7</a> + */ +public class MediaTypeConst { + + public final static String WILDCARD = "*/*"; + + public final static String APPLICATION_XML = "application/xml"; + + public final static String APPLICATION_ATOM_XML = "application/atom+xml"; + + public final static String APPLICATION_XHTML_XML = "application/xhtml+xml"; + + public final static String APPLICATION_SVG_XML = "application/svg+xml"; + + public final static String APPLICATION_JSON = "application/json"; + + public final static String APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"; + + public final static String MULTIPART_FORM_DATA = "multipart/form-data"; + + public final static String APPLICATION_OCTET_STREAM = "application/octet-stream"; + + public final static String TEXT_PLAIN = "text/plain"; + + public final static String TEXT_XML = "text/xml"; + + public final static String TEXT_HTML = "text/html"; + + public final static String SERVER_SENT_EVENTS = "text/event-stream"; + + public final static String APPLICATION_JSON_PATCH_JSON = "application/json-patch+json"; +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OasContext.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OasContext.java new file mode 100644 index 0000000..3be7edb --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OasContext.java @@ -0,0 +1,151 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.toolkit.generator.parser.api.OpenApiAnnotationParser; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.PathItem.HttpMethod; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.servers.Server; + +public class OasContext { + + private OpenAPI openAPI; + + private String basePath; + + private Class<?> cls; + + private List<OperationContext> operationList = new ArrayList<>(); + + private OpenApiAnnotationParser parser; + + public OasContext(OpenApiAnnotationParser parser) { + this(new OpenAPI(), parser); + } + + public OasContext(OpenAPI openAPI, OpenApiAnnotationParser parser) { + this.openAPI = openAPI; + this.parser = parser; + } + + public OpenAPI toOpenAPI() { + ensurePaths(); + for (OperationContext operationCtx : operationList) { + if (!operationCtx.hasOperation()) { + continue; + } + + if (openAPI.getPaths() == null) { + openAPI.setPaths(new Paths()); + } + + PathItem pathItem = openAPI.getPaths().get(operationCtx.getPath()); + if (pathItem == null) { + pathItem = new PathItem(); + openAPI.path(operationCtx.getPath(), pathItem); + } + pathItem.operation(HttpMethod.valueOf(operationCtx.getHttpMethod()), operationCtx.toOperation()); + } + + // 如果没有restful资源则返回null + if (openAPI.getPaths() == null || openAPI.getPaths().size() == 0) { + return null; + } + + openAPI.info(new Info().title("gen").version("1.0.0")); + + correctBasepath(); + correctComponents(); + + openAPI.servers(Collections.singletonList(new Server().url(basePath))); + + return openAPI; + } + + private void correctComponents() { + Components nullComponents = new Components(); + if (nullComponents.equals(getComponents())) { + openAPI.setComponents(null); + } + } + + private void correctBasepath() { + if (StringUtils.isEmpty(basePath)) { + basePath = "/"; + } + + if (!basePath.startsWith("/")) { + basePath = "/" + basePath; + } + } + + public Components getComponents() { + if (openAPI.getComponents() == null) { + openAPI.setComponents(new Components()); + } + return openAPI.getComponents(); + } + + private void ensurePaths() { + if (openAPI.getPaths() == null) { + openAPI.setPaths(new Paths()); + } + } + + public OpenApiAnnotationParser getParser() { + return parser; + } + + public void setParser(OpenApiAnnotationParser parser) { + this.parser = parser; + } + + public OpenAPI getOpenAPI() { + return openAPI; + } + + public String getBasePath() { + return basePath; + } + + public Class<?> getCls() { + return cls; + } + + public void setCls(Class<?> cls) { + this.cls = cls; + } + + public void setBasePath(String basePath) { + this.basePath = basePath; + } + + public void addOperation(OperationContext operation) { + operationList.add(operation); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OasGenerator.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OasGenerator.java new file mode 100644 index 0000000..540f320 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OasGenerator.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.ServiceLoader; +import java.util.Set; + +import org.apache.servicecomb.toolkit.generator.parser.api.OpenApiAnnotationParser; + +import io.swagger.v3.oas.models.OpenAPI; + +public class OasGenerator { + + private static List<OpenApiAnnotationParser> parserList = new ArrayList<>(); + + static { + ServiceLoader.load(OpenApiAnnotationParser.class).forEach(parserList::add); + } + + public OpenAPI generate(Class<?> cls) { + + Optional<OpenApiAnnotationParser> parserOptional = parserList.stream().filter(parser -> parser.canProcess(cls)) + .findFirst(); + + if (!parserOptional.isPresent()) { + return null; + } + OasContext context = new OasContext(parserOptional.get()); + parserOptional.get().parser(cls, context); + return context.toOpenAPI(); + } + + public List<OpenAPI> generate(Set<Class> classes) { + + List<OpenAPI> openApiList = new ArrayList<>(); + for (Class cls : classes) { + OpenAPI openAPI = generate(cls); + if (openAPI != null) { + openApiList.add(openAPI); + } + } + + return openApiList; + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OperationContext.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OperationContext.java new file mode 100644 index 0000000..b8bca12 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/OperationContext.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.toolkit.generator.parser.api.OpenApiAnnotationParser; +import org.apache.servicecomb.toolkit.generator.util.ModelConverter; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; + +public class OperationContext { + + private OasContext parentContext; + + private Method method; + + private Operation operation = new Operation(); + + private String operationId; + + private String path; + + private String httpMethod; + + private ApiResponses apiResponses = new ApiResponses(); + + private List<ParameterContext> parameterContextList = new ArrayList<>(); + + private OpenApiAnnotationParser parser; + + public OperationContext(Method method, OasContext parentContext) { + this.parentContext = parentContext; + this.method = method; + this.parser = parentContext.getParser(); + this.parentContext.addOperation(this); + } + + public void addParameter(ParameterContext context) { + parameterContextList.add(context); + } + + public OpenApiAnnotationParser getParser() { + return parser; + } + + public boolean hasOperation() { + return httpMethod != null && method != null; + } + + public Operation toOperation() { + + if (!hasOperation()) { + return null; + } + + if (StringUtils.isEmpty(operationId)) { + operationId = method.getName(); + } + + operation.operationId(operationId); + correctResponse(apiResponses); + operation.setResponses(apiResponses); + + // 处理参数 + List<Parameter> parameterList = parameterContextList.stream() + .map(parameterContext -> parameterContext.toOasParameter()) + .filter(parameter -> parameter != null) + .collect(Collectors.toList()); + + if (parameterList.size() > 0) { + operation.parameters(parameterList); + } + + return operation; + } + + public void correctResponse(ApiResponses apiResponses) { + + if (apiResponses == null) { + return; + } + // 处理响应 + // 没有注解被处理 + if (apiResponses.get(HttpStatus.OK) == null) { + ApiResponse apiResponse = new ApiResponse(); + + Class<?> returnType = method.getReturnType(); + if (returnType == Void.TYPE || returnType == Void.class) { + return; + } + + MediaType mediaType = new MediaType(); + + Schema refSchema = ModelConverter.getSchema(returnType, getComponents()); + mediaType.schema(refSchema); + + Content content = new Content(); + content.addMediaType(MediaTypeConst.TEXT_PLAIN, mediaType); + + apiResponse.description("OK"); + apiResponse.setContent(content); + apiResponses.addApiResponse(HttpStatus.OK, apiResponse); + } + } + + public Components getComponents() { + return parentContext.getComponents(); + } + + public void addResponse(String key, ApiResponse response) { + apiResponses.addApiResponse(key, response); + } + + public ApiResponses getApiResponses() { + return apiResponses; + } + + public void setApiResponses(ApiResponses apiResponses) { + this.apiResponses = apiResponses; + } + + public String getOperationId() { + return operationId; + } + + public void setOperationId(String operationId) { + this.operationId = operationId; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Operation getOperation() { + return operation; + } + + public OpenAPI getOpenAPI() { + return parentContext.getOpenAPI(); + } + + public Method getMethod() { + return method; + } + + public OasContext getOpenApiContext() { + return parentContext; + } + + public String getHttpMethod() { + return httpMethod; + } + + public void setHttpMethod(String httpMethod) { + if (this.httpMethod != null) { + throw new IllegalArgumentException(String.format("too many http method in the method %s", method.getName())); + } + this.httpMethod = httpMethod.toUpperCase(); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/ParameterContext.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/ParameterContext.java new file mode 100644 index 0000000..15e6721 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/ParameterContext.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import java.lang.reflect.Parameter; +import java.lang.reflect.Type; + +import org.apache.servicecomb.toolkit.generator.util.ModelConverter; +import org.apache.servicecomb.toolkit.generator.util.ParamUtils; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.media.Schema; + +public class ParameterContext { + + private OperationContext parentContext; + + private boolean required; + + private String name; + + Parameter parameter; + + private Object defaultValue; + + + io.swagger.v3.oas.models.parameters.Parameter oasParameter = new io.swagger.v3.oas.models.parameters.Parameter(); + + public ParameterContext(OperationContext parentContext, Parameter parameter) { + this.parentContext = parentContext; + this.parameter = parameter; + this.parentContext.addParameter(this); + } + + + public io.swagger.v3.oas.models.parameters.Parameter toOasParameter() { + + if (parameter == null) { + return null; + } + ensureName(); + if (oasParameter.getSchema() == null) { + Schema refSchema = ModelConverter.getSchema(parameter.getType(), getComponents()); + oasParameter.schema(refSchema); + } + + if (oasParameter.getIn() == null) { + oasParameter.setIn(ParameterIn.QUERY.toString()); + } + + if (defaultValue != null) { + required = false; + oasParameter.getSchema().setDefault(defaultValue); + } + + oasParameter.setRequired(required); + + return oasParameter; + } + + private void ensureName() { + if (name == null) { + // 尝试获取实际参数名 + name = ParamUtils.getParamterName(parentContext.getMethod(), parameter); + } + + if (name == null) { + name = parameter.getName(); + } + + oasParameter.setName(name); + } + + public OperationContext getOperationContext() { + return parentContext; + } + + public Type getActualType() { + return parameter.getParameterizedType(); + } + + public Object getDefaultValue() { + return defaultValue; + } + + public void setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; + } + + public Components getComponents() { + return parentContext.getComponents(); + } + + public io.swagger.v3.oas.models.parameters.Parameter getOasParameter() { + return oasParameter; + } + + public Parameter getParameter() { + return parameter; + } + + public void setParameter(Parameter parameter) { + this.parameter = parameter; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isRequired() { + return required; + } + + public void setRequired(boolean required) { + this.required = required; + } + + public void setType(String type) { + oasParameter.setIn(type); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/AnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/AnnotationProcessor.java new file mode 100644 index 0000000..5827b55 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/AnnotationProcessor.java @@ -0,0 +1,22 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +public interface AnnotationProcessor<Annotation, Context> { + void process(Annotation annotation, Context context); +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ApiResponseMethodAnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ApiResponseMethodAnnotationProcessor.java new file mode 100644 index 0000000..3cbbe0a --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ApiResponseMethodAnnotationProcessor.java @@ -0,0 +1,63 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.toolkit.generator.OperationContext; + +import io.swagger.v3.oas.annotations.headers.Header; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.models.media.MediaType; + +public class ApiResponseMethodAnnotationProcessor implements + MethodAnnotationProcessor<ApiResponse, OperationContext> { + @Override + public void process(ApiResponse response, OperationContext context) { + + io.swagger.v3.oas.models.responses.ApiResponse apiResponse = new io.swagger.v3.oas.models.responses.ApiResponse(); + + Content[] contentAnnotations = response.content(); + Optional.ofNullable(contentAnnotations).ifPresent(contents -> { + for (Content contentAnnotation : contents) { + io.swagger.v3.oas.models.media.Content content = new io.swagger.v3.oas.models.media.Content(); + MediaType mediaType = new MediaType(); + content.addMediaType(contentAnnotation.mediaType(), mediaType); + apiResponse.setContent(content); + } + }); + + if (StringUtils.isNotEmpty(response.description())) { + apiResponse.setDescription(response.description()); + } + + Header[] headersAnnotation = response.headers(); + Optional.ofNullable(headersAnnotation).ifPresent(headers -> { + for (Header headerAnnotation : headers) { + io.swagger.v3.oas.models.headers.Header header = new io.swagger.v3.oas.models.headers.Header(); + header.description(headerAnnotation.description()); + header.deprecated(headerAnnotation.deprecated()); + apiResponse.addHeaderObject(headerAnnotation.name(), header); + } + }); + + context.addResponse(response.responseCode(), apiResponse); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ApiResponsesMethodAnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ApiResponsesMethodAnnotationProcessor.java new file mode 100644 index 0000000..54747ae --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ApiResponsesMethodAnnotationProcessor.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +import java.util.Arrays; + +import org.apache.servicecomb.toolkit.generator.OperationContext; + +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +public class ApiResponsesMethodAnnotationProcessor implements + MethodAnnotationProcessor<ApiResponses, OperationContext> { + @Override + public void process(ApiResponses responses, OperationContext context) { + + MethodAnnotationProcessor apiResponseAnnotationProcessor = context.getParser() + .findMethodAnnotationProcessor(ApiResponse.class); + + if (apiResponseAnnotationProcessor != null) { + Arrays.stream(responses.value()).forEach(response -> apiResponseAnnotationProcessor.process(response, context)); + } + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ClassAnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ClassAnnotationProcessor.java new file mode 100644 index 0000000..55d11be --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ClassAnnotationProcessor.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +public interface ClassAnnotationProcessor<Annotation, Context> extends AnnotationProcessor<Annotation, Context> { +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/MethodAnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/MethodAnnotationProcessor.java new file mode 100644 index 0000000..cff77a6 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/MethodAnnotationProcessor.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +public interface MethodAnnotationProcessor<Annotation, Context> extends AnnotationProcessor<Annotation, Context> { +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ModelInterceptor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ModelInterceptor.java new file mode 100644 index 0000000..8415e1a --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ModelInterceptor.java @@ -0,0 +1,28 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.media.Schema; + +public interface ModelInterceptor { + + int order(); + + Schema process(Class<?> cls, Components components); +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/OperationMethodAnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/OperationMethodAnnotationProcessor.java new file mode 100644 index 0000000..517ea5b --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/OperationMethodAnnotationProcessor.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +import org.apache.servicecomb.toolkit.generator.OperationContext; + +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.extensions.Extension; +import io.swagger.v3.oas.annotations.parameters.RequestBody; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.servers.Server; + +public class OperationMethodAnnotationProcessor implements MethodAnnotationProcessor<Operation, OperationContext> { + + @Override + public void process(Operation annotation, OperationContext context) { + + context.setOperationId(annotation.operationId()); + String s = annotation.operationId(); + boolean deprecated = annotation.deprecated(); + String description = annotation.description(); + Extension[] extensions = annotation.extensions(); + ExternalDocumentation externalDocumentation = annotation.externalDocs(); + RequestBody requestBody = annotation.requestBody(); + ApiResponse[] responses = annotation.responses(); + String method = annotation.method(); + Server[] servers = annotation.servers(); + SecurityRequirement[] security = annotation.security(); + String[] tags = annotation.tags(); + String summary = annotation.summary(); + Parameter[] parameters = annotation.parameters(); + +// context.getOpenAPI().setPaths(); + + // responseReference未解析 + // hidden未解析 + // authorizations未解析 + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ParamAnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ParamAnnotationProcessor.java new file mode 100644 index 0000000..5b2b393 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ParamAnnotationProcessor.java @@ -0,0 +1,21 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +public interface ParamAnnotationProcessor<Annotation, ParameterContext> extends AnnotationProcessor<Annotation, ParameterContext> { +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ParameterAnnotationProcessor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ParameterAnnotationProcessor.java new file mode 100644 index 0000000..139bb0b --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/annotation/ParameterAnnotationProcessor.java @@ -0,0 +1,53 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.annotation; + +import java.lang.reflect.Type; +import java.util.Arrays; + +import org.apache.commons.lang3.StringUtils; +import org.apache.servicecomb.toolkit.generator.ParameterContext; + +import io.swagger.v3.core.util.ParameterProcessor; +import io.swagger.v3.core.util.ReflectionUtils; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Schema; + +public class ParameterAnnotationProcessor implements ParamAnnotationProcessor<Parameter, ParameterContext> { + + @Override + public void process(Parameter parameter, ParameterContext parameterContext) { + + Schema schema = parameter.schema(); + Type type = parameterContext.getActualType(); + if (schema != null) { + + if (StringUtils.isNotEmpty(schema.type())) { + parameterContext.setType(schema.type()); + type = ReflectionUtils.typeFromString(schema.type()); + } + } + + ParameterProcessor + .applyAnnotations(parameterContext.getOasParameter(), type, Arrays.asList(parameter), + parameterContext.getComponents(), + null, null, null); + + parameterContext.setRequired(parameter.required()); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/parser/AbstractAnnotationParser.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/parser/AbstractAnnotationParser.java new file mode 100644 index 0000000..5b3a4fa --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/parser/AbstractAnnotationParser.java @@ -0,0 +1,152 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.parser; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.servicecomb.toolkit.generator.OasContext; +import org.apache.servicecomb.toolkit.generator.OperationContext; +import org.apache.servicecomb.toolkit.generator.ParameterContext; +import org.apache.servicecomb.toolkit.generator.annotation.AnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ApiResponseMethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ApiResponsesMethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ClassAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.MethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.OperationMethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ParamAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ParameterAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.parser.api.OpenApiAnnotationParser; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; + +public abstract class AbstractAnnotationParser implements OpenApiAnnotationParser { + + private Class<?> cls; + + private OasContext context; + + protected Map<Class, ClassAnnotationProcessor> classAnnotationMap = new HashMap<>(); + + protected Map<Class, MethodAnnotationProcessor> methodAnnotationMap = new HashMap<>(); + + protected Map<Class, ParamAnnotationProcessor> parameterAnnotationMap = new HashMap<>(); + + public AbstractAnnotationParser() { + initMethodAnnotationProcessor(); + initClassAnnotationProcessor(); + initParameterAnnotationProcessor(); + } + + @Override + public void parser(Class<?> cls, OasContext context) { + + this.cls = cls; + this.context = context; + + if (!canProcess(cls)) { + return; + } + + for (Annotation clsAnnotation : cls.getAnnotations()) { + AnnotationProcessor annotationProcessor = classAnnotationMap.get(clsAnnotation.annotationType()); + if (annotationProcessor == null) { + continue; + } + annotationProcessor.process(clsAnnotation, context); + } + postParseClassAnnotaion(context); + + List<Method> methods = Arrays.asList(cls.getDeclaredMethods()); + methods.sort(Comparator.comparing(Method::getName)); + for (Method m : methods) { + OperationContext operationContext = new OperationContext(m, context); + for (Annotation methodAnnotation : m.getAnnotations()) { + MethodAnnotationProcessor annotationProcessor = methodAnnotationMap.get(methodAnnotation.annotationType()); + if (annotationProcessor != null) { + annotationProcessor.process(methodAnnotation, operationContext); + } + } + + postParseMethodAnnotation(operationContext); + + java.lang.reflect.Parameter[] parameters = m.getParameters(); + + for (java.lang.reflect.Parameter parameter : parameters) { + ParameterContext parameterContext = new ParameterContext(operationContext, parameter); + for (Annotation paramAnnotation : parameter.getAnnotations()) { + ParamAnnotationProcessor paramAnnotationProcessor = parameterAnnotationMap + .get(paramAnnotation.annotationType()); + if (paramAnnotationProcessor != null) { + paramAnnotationProcessor.process(paramAnnotation, parameterContext); + } + } + postParseParameterAnnotation(parameterContext); + } + } + } + + @Override + public void postParseClassAnnotaion(OasContext context) { + } + + @Override + public void postParseMethodAnnotation(OperationContext context) { + } + + @Override + public void postParseParameterAnnotation(ParameterContext context) { + } + + public void initMethodAnnotationProcessor() { + methodAnnotationMap.put(Operation.class, new OperationMethodAnnotationProcessor()); + methodAnnotationMap.put(ApiResponse.class, new ApiResponseMethodAnnotationProcessor()); + methodAnnotationMap.put(ApiResponses.class, new ApiResponsesMethodAnnotationProcessor()); + } + + public void initClassAnnotationProcessor() { + + } + + public void initParameterAnnotationProcessor() { + parameterAnnotationMap.put(Parameter.class, new ParameterAnnotationProcessor()); + } + + @Override + public ClassAnnotationProcessor findClassAnnotationProcessor(Class<? extends Annotation> annotationType) { + return classAnnotationMap.get(annotationType); + } + + @Override + public MethodAnnotationProcessor findMethodAnnotationProcessor(Class<? extends Annotation> annotationType) { + return methodAnnotationMap.get(annotationType); + } + + @Override + public ParamAnnotationProcessor findParameterAnnotationProcessor(Class<? extends Annotation> annotationType) { + return parameterAnnotationMap.get(annotationType); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/parser/api/OpenApiAnnotationParser.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/parser/api/OpenApiAnnotationParser.java new file mode 100644 index 0000000..1fbdd9e --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/parser/api/OpenApiAnnotationParser.java @@ -0,0 +1,57 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.parser.api; + +import java.lang.annotation.Annotation; + +import org.apache.servicecomb.toolkit.generator.OasContext; +import org.apache.servicecomb.toolkit.generator.OperationContext; +import org.apache.servicecomb.toolkit.generator.ParameterContext; +import org.apache.servicecomb.toolkit.generator.annotation.ClassAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.MethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ParamAnnotationProcessor; + +public interface OpenApiAnnotationParser { + + /** + * + * @param cls + * @param context + */ + void parser(Class<?> cls, OasContext context); + + /** + * 用于排序, 对于同一个类,同时只能为springmvc或者jaxrs其中一种 + * @return + */ + int getOrder(); + + boolean canProcess(Class<?> cls); + + void postParseClassAnnotaion(OasContext context); + + void postParseMethodAnnotation(OperationContext context); + + void postParseParameterAnnotation(ParameterContext context); + + ClassAnnotationProcessor findClassAnnotationProcessor(Class<? extends Annotation> annotationType); + + MethodAnnotationProcessor findMethodAnnotationProcessor(Class<? extends Annotation> annotationType); + + ParamAnnotationProcessor findParameterAnnotationProcessor(Class<? extends Annotation> annotationType); +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ArrayModelConverter.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ArrayModelConverter.java new file mode 100644 index 0000000..f52c57d --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ArrayModelConverter.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.util; + +import java.util.Iterator; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.type.TypeFactory; + +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverter; +import io.swagger.v3.core.converter.ModelConverterContext; +import io.swagger.v3.core.jackson.AbstractModelConverter; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; + +public class ArrayModelConverter extends AbstractModelConverter { + + protected ArrayModelConverter(ObjectMapper mapper) { + super(mapper); + } + + @Override + public Schema resolve(AnnotatedType type, ModelConverterContext context, Iterator<ModelConverter> chain) { + + String typeName = _typeName(TypeFactory.defaultInstance().constructType(type.getType())); + + ArraySchema schema; + if ("Array".equals(typeName)) { + schema = new ArraySchema(); + if (!(type.getType() instanceof Class)) { + return null; + } + Schema itemSchema = context.resolve(new AnnotatedType(((Class) type.getType()).getComponentType())); + schema.setItems(itemSchema); + return schema; + } + return super.resolve(type, context, chain); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/LocalVariableVisitor.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/LocalVariableVisitor.java new file mode 100644 index 0000000..b7f19c1 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/LocalVariableVisitor.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.util; + +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; + +public class LocalVariableVisitor extends MethodVisitor { + + private boolean isStatic; + + private String[] parameterNames; + + private final int[] lvtSlotIndex; + + private final Type[] args; + + public LocalVariableVisitor(int api, String desc, boolean isStatic, String[] parameterNames) { + super(api); + this.isStatic = isStatic; + this.parameterNames = parameterNames; + this.args = Type.getArgumentTypes(desc); + this.lvtSlotIndex = computeLvtSlotIndices(isStatic, this.args); + } + + @Override + public void visitLocalVariable(String name, String descriptor, String signature, Label start, Label end, + int index) { + + for (int i = 0; i < this.lvtSlotIndex.length; i++) { + if (this.lvtSlotIndex[i] == index) { + this.parameterNames[i] = name; + } + } + super.visitLocalVariable(name, descriptor, signature, start, end, index); + } + + int[] computeLvtSlotIndices(boolean isStatic, Type[] paramTypes) { + int[] lvtIndex = new int[paramTypes.length]; + int nextIndex = (isStatic ? 0 : 1); + for (int i = 0; i < paramTypes.length; i++) { + lvtIndex[i] = nextIndex; + if (isWideType(paramTypes[i])) { + nextIndex += 2; + } else { + nextIndex++; + } + } + return lvtIndex; + } + + private boolean isWideType(Type aType) { + return (aType == Type.LONG_TYPE || aType == Type.DOUBLE_TYPE); + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ModelConverter.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ModelConverter.java new file mode 100644 index 0000000..0370c31 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ModelConverter.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.util; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.ServiceLoader; + +import org.apache.servicecomb.toolkit.generator.annotation.ModelInterceptor; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverterContextImpl; +import io.swagger.v3.core.jackson.ModelResolver; +import io.swagger.v3.core.util.PrimitiveType; +import io.swagger.v3.core.util.RefUtils; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; + +public class ModelConverter { + + private static final ModelConverterContextImpl context; + + private static final List<ModelInterceptor> interceptorMgr = new ArrayList<>(); + + static { + + ServiceLoader.load(ModelInterceptor.class).forEach(ModelConverter::registerInterceptor); + + ArrayModelConverter arrayModelConverter = new ArrayModelConverter(mapper()); + ModelResolver modelResolver = new ModelResolver(mapper()); + + context = new ModelConverterContextImpl(Arrays.asList(arrayModelConverter, modelResolver)); + } + + public static void registerInterceptor(ModelInterceptor interceptor) { + interceptorMgr.add(interceptor); + interceptorMgr.sort(Comparator.comparingInt(ModelInterceptor::order)); + } + + public static Schema getSchema(Class<?> cls) { + return getSchema(cls, null); + } + + public static Schema getSchema(Class<?> cls, Components components) { + + for (ModelInterceptor interceptor : interceptorMgr) { + Schema schema = interceptor.process(cls, components); + if (schema != null) { + return schema; + } + } + + Schema schema = PrimitiveType.createProperty(cls); + if (schema == null) { + schema = context + .resolve(new AnnotatedType(cls)); + } + + if (components == null) { + return schema; + } + + Schema refSchema = schema; + + if (shouldExtractRef(schema)) { + ensureSchemaNameExist(schema); + schema.$ref(null); + components.addSchemas(schema.getName(), schema); + refSchema = new Schema(); + refSchema.set$ref(RefUtils.constructRef(schema.getName())); + } + + if (schema instanceof ArraySchema) { + ArraySchema arraySchema = (ArraySchema) schema; + Schema itemSchema = arraySchema.getItems(); + if (shouldExtractRef(itemSchema)) { + ensureSchemaNameExist(itemSchema); + itemSchema.$ref(null); + components.addSchemas(itemSchema.getName(), itemSchema); + + Schema itemRefSchema = new Schema(); + itemRefSchema.set$ref(RefUtils.constructRef(itemSchema.getName())); + arraySchema.setItems(itemRefSchema); + } + + refSchema = arraySchema; + } + + return refSchema; + } + + private static void ensureSchemaNameExist(Schema schema) { + if (schema.getName() != null) { + return; + } + + if (schema.get$ref() != null) { + schema.setName((String) RefUtils.extractSimpleName(schema.get$ref()).getKey()); + return; + } + } + + public static boolean shouldExtractRef(Schema schema) { + if (schema.getName() != null || schema.get$ref() != null) { + return true; + } + return false; + } + + + public static ObjectMapper mapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + + return mapper; + } +} diff --git a/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ParamUtils.java b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ParamUtils.java new file mode 100644 index 0000000..9093630 --- /dev/null +++ b/oas-generator/oas-generator-core/src/main/java/org/apache/servicecomb/toolkit/generator/util/ParamUtils.java @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator.util; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; +import java.util.HashMap; +import java.util.Map; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; + +public class ParamUtils { + + private static final String STATIC_CLASS_INIT = "<clinit>"; + + public static final Map<Method, String[]> paramterCache = new HashMap(); + + public static String getParamterName(Method method, Parameter parameter) { + + String[] parameterNames = paramterCache.get(method); + + if (parameterNames == null) { + parameterNames = initParamterNames(method); + if (parameterNames == null) { + return null; + } + } + + int paramIndex = getParamIndex(method, parameter); + if (paramIndex >= 0) { + return parameterNames[paramIndex]; + } + + return null; + } + + private static int getParamIndex(Method method, Parameter parameter) { + Parameter[] parameters = method.getParameters(); + for (int i = 0; i < parameters.length; i++) { + if (parameters[i].equals(parameter)) { + return i; + } + } + return -1; + } + + private static String[] initParamterNames(Method m) { + + boolean isStatic = Modifier.isStatic(m.getModifiers()); + String[] paramterNames = new String[m.getParameterCount()]; + + try { + + String className = m.getDeclaringClass().getName(); + String classRawName = className.replace('.', '/') + ".class"; + + InputStream is = null; + ClassLoader classLoader = m.getDeclaringClass().getClassLoader(); + if (classLoader != null) { + is = classLoader.getResourceAsStream(classRawName); + } else { + is = m.getDeclaringClass().getResourceAsStream(classRawName); + } + + if (is == null) { + return null; + } + ClassReader clsReader = new ClassReader(is); + ClassWriter clsWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); + + clsReader.accept(new ClassVisitor(Opcodes.ASM7, clsWriter) { + @Override + public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, + String[] exceptions) { + MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions); + if (!m.getName().equals(name) || !descriptor.equals(Type.getMethodDescriptor(m))) { + return methodVisitor; + } + + if (!isSyntheticOrBridged(access) && !STATIC_CLASS_INIT.equals(name)) { + return new LocalVariableVisitor(this.api, descriptor, isStatic, paramterNames); + } + + return methodVisitor; + } + }, 0); + } catch (IOException e) { + e.printStackTrace(); + } + + paramterCache.put(m, paramterNames); + + return paramterNames; + } + + private static boolean isSyntheticOrBridged(int access) { + return (((access & Opcodes.ACC_SYNTHETIC) | (access & Opcodes.ACC_BRIDGE)) > 0); + } +} diff --git a/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/AnnotationProcessorTest.java b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/AnnotationProcessorTest.java new file mode 100644 index 0000000..c6bbf56 --- /dev/null +++ b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/AnnotationProcessorTest.java @@ -0,0 +1,129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import java.lang.reflect.Method; + +import org.apache.servicecomb.toolkit.generator.annotation.ApiResponseMethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ApiResponsesMethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.OperationMethodAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.annotation.ParameterAnnotationProcessor; +import org.apache.servicecomb.toolkit.generator.parser.AbstractAnnotationParser; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.models.media.StringSchema; + +public class AnnotationProcessorTest { + + @Test + public void processApiResponseAnnotation() { + + OasContext oasContext = new OasContext(null); + OperationContext context = new OperationContext(null, oasContext); + ApiResponseMethodAnnotationProcessor apiResProcessor = new ApiResponseMethodAnnotationProcessor(); + ApiResponse apiResponse = Mockito.mock(ApiResponse.class); + Content[] contents = new Content[1]; + contents[0] = Mockito.mock(Content.class); + Mockito.when(contents[0].mediaType()).thenReturn(MediaTypeConst.APPLICATION_JSON); + Mockito.when(apiResponse.content()).thenReturn(contents); + Mockito.when(apiResponse.responseCode()).thenReturn("200"); + apiResProcessor.process(apiResponse, context); + + Assert.assertNotNull(context.getApiResponses().get("200")); + Assert.assertNull(context.getApiResponses().get("500")); + } + + @Test + public void processApiResponsesAnnotation() { + + OasContext oasContext = new OasContext(new AbstractAnnotationParser() { + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean canProcess(Class<?> cls) { + return true; + } + }); + + OperationContext context = new OperationContext(null, oasContext); + ApiResponsesMethodAnnotationProcessor apiRessProcessor = new ApiResponsesMethodAnnotationProcessor(); + ApiResponses apiResponses = Mockito.mock(ApiResponses.class); + Content[] contents = new Content[1]; + contents[0] = Mockito.mock(Content.class); + Mockito.when(contents[0].mediaType()).thenReturn(MediaTypeConst.APPLICATION_JSON); + ApiResponse apiResponse = Mockito.mock(ApiResponse.class); + Mockito.when(apiResponse.content()).thenReturn(contents); + Mockito.when(apiResponse.responseCode()).thenReturn("200"); + Mockito.when(apiResponses.value()).thenReturn(new ApiResponse[] {apiResponse}); + + apiRessProcessor.process(apiResponses, context); + + Assert.assertNotNull(context.getApiResponses().get("200")); + Assert.assertNull(context.getApiResponses().get("500")); + } + + @Test + public void processOperationAnnotation() { + + OasContext oasContext = new OasContext(null); + OperationContext context = new OperationContext(null, oasContext); + OperationMethodAnnotationProcessor operationMethodAnnotationProcessor = new OperationMethodAnnotationProcessor(); + Operation operation = Mockito.mock(Operation.class); + operationMethodAnnotationProcessor.process(operation, context); + } + + + @Test + public void processParameterAnnotation() throws NoSuchMethodException, IllegalAccessException, + InstantiationException { + + OasContext oasContext = new OasContext(null); + Method parameterMethod = ParameterClass.class.getMethod("parameter", String.class); + OperationContext operationContext = new OperationContext(parameterMethod, oasContext); + java.lang.reflect.Parameter[] parameters = parameterMethod.getParameters(); + Assert.assertEquals(parameters.length, 1); + java.lang.reflect.Parameter parameter = parameters[0]; + Parameter parameterDeclaredAnnotation = parameter.getDeclaredAnnotation(Parameter.class); + + ParameterContext parameterContext = new ParameterContext(operationContext, parameter); + ParameterAnnotationProcessor parameterAnnotationProcessor = new ParameterAnnotationProcessor(); + + parameterAnnotationProcessor.process(parameterDeclaredAnnotation, parameterContext); + io.swagger.v3.oas.models.parameters.Parameter oasParameter = parameterContext.toOasParameter(); + Assert.assertEquals("param", oasParameter.getName()); + Assert.assertEquals(StringSchema.class, oasParameter.getSchema().getClass()); + Assert.assertTrue(parameterContext.isRequired()); + Assert.assertEquals(operationContext, parameterContext.getOperationContext()); + Assert.assertNull(parameterContext.getDefaultValue()); + } + + class ParameterClass { + public void parameter(@Parameter(required = true) String param) { + } + } +} diff --git a/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/OasGeneratorTest.java b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/OasGeneratorTest.java new file mode 100644 index 0000000..d454d7d --- /dev/null +++ b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/OasGeneratorTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; +import java.util.HashSet; +import java.util.Set; + +import org.junit.Assert; +import org.junit.Test; + +import io.swagger.v3.oas.annotations.enums.ParameterIn; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.PathItem.HttpMethod; + +public class OasGeneratorTest { + + @Test + public void generatorOas() { + + Set<Class> classSet = new HashSet<>(); + classSet.add(NoResource.class); + classSet.add(OneResource.class); + OasGenerator generator = new OasGenerator(); + generator.generate(classSet); + } + + @Test + public void constructOasContext() throws NoSuchMethodException { + OasContext oasContext = new OasContext(null); + + Method method = OneResource.class.getMethod("name", String.class); + OperationContext operationContext = new OperationContext(method, oasContext); + operationContext.setHttpMethod(HttpMethod.GET.name()); + operationContext.setOperationId(method.getName()); + operationContext.setPath("/operation"); + + oasContext.addOperation(operationContext); + oasContext.setCls(method.getDeclaringClass()); + oasContext.setBasePath("/oas"); + oasContext.setParser(null); + + Assert.assertEquals("/oas", oasContext.getBasePath()); + Assert.assertEquals(method.getDeclaringClass(), oasContext.getCls()); + Assert.assertNull(oasContext.getParser()); + + Assert.assertEquals("/operation", operationContext.getPath()); + Assert.assertEquals(HttpMethod.GET.name(), operationContext.getHttpMethod()); + Assert.assertEquals(oasContext.getComponents(), operationContext.getComponents()); + Assert.assertEquals(null, operationContext.getApiResponses().getDefault()); + Assert.assertEquals(oasContext.getOpenAPI(), operationContext.getOpenAPI()); + + Parameter parameter = method.getParameters()[0]; + ParameterContext parameterContext = new ParameterContext(operationContext, parameter); + parameterContext.setName(parameter.getName()); + parameterContext.setRequired(true); + parameterContext.setType(ParameterIn.QUERY.toString()); + + Assert.assertEquals(parameter.getName(), parameterContext.getName()); + + OpenAPI openAPI = oasContext.toOpenAPI(); + Assert.assertNotNull(openAPI); + } + + class NoResource { + + } + + class OneResource { + public String name(String name) { + return name; + } + } +} diff --git a/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/ParserTest.java b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/ParserTest.java new file mode 100644 index 0000000..c0b37e3 --- /dev/null +++ b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/ParserTest.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import org.apache.servicecomb.toolkit.generator.parser.AbstractAnnotationParser; +import org.junit.Test; + +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.responses.ApiResponse; + +public class ParserTest { + + @Test + public void parse() { + AbstractAnnotationParser parser = new TestParser(); + + parser.parser(UnParser.class, new OasContext(parser)); + } + + class TestParser extends AbstractAnnotationParser { + + @Override + public int getOrder() { + return 0; + } + + @Override + public boolean canProcess(Class<?> cls) { + return true; + } + } + + @OpenAPIDefinition + class UnParser { + @ApiResponse + public String name(String name) { + return name; + } + } +} diff --git a/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/UtilsTest.java b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/UtilsTest.java new file mode 100644 index 0000000..224dbf9 --- /dev/null +++ b/oas-generator/oas-generator-core/src/test/java/org/apache/servicecomb/toolkit/generator/UtilsTest.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.servicecomb.toolkit.generator; + +import java.lang.reflect.Method; +import java.lang.reflect.Parameter; + +import org.apache.servicecomb.toolkit.generator.annotation.ModelInterceptor; +import org.apache.servicecomb.toolkit.generator.util.ModelConverter; +import org.apache.servicecomb.toolkit.generator.util.ParamUtils; +import org.junit.Assert; +import org.junit.Test; + +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.media.StringSchema; + +public class UtilsTest { + + @Test + public void getParameterName() throws NoSuchMethodException { + + Method method = ParameterClass.class.getMethod("method", String.class); + Parameter parameter = method.getParameters()[0]; + String paramterName = ParamUtils.getParamterName(method, parameter); + Assert.assertEquals("param", paramterName); + } + + @Test + public void getSchema() { + Schema schema = ModelConverter.getSchema(String.class); + Assert.assertEquals(StringSchema.class, schema.getClass()); + + schema = ModelConverter.getSchema(ParameterClass.class); + Assert.assertEquals(Schema.class, schema.getClass()); + + schema = ModelConverter.getSchema(String[].class); + Assert.assertEquals(ArraySchema.class, schema.getClass()); + + Components components = new Components(); + schema = ModelConverter.getSchema(ParameterClass[].class, components); + Assert.assertEquals(ArraySchema.class, schema.getClass()); + + schema = ModelConverter.getSchema(ParameterClass.class, components); + Assert.assertNotNull(schema.get$ref()); + + ModelConverter.registerInterceptor(new ModelInterceptor() { + @Override + public int order() { + return 0; + } + + @Override + public Schema process(Class<?> cls, Components components) { + return new Schema().name("unknown"); + } + }); + + schema = ModelConverter.getSchema(ParameterClass.class); + Assert.assertEquals("unknown", schema.getName()); + } + + class ParameterClass { + public void method(String param) { + } + } +} diff --git a/oas-generator/pom.xml b/oas-generator/pom.xml new file mode 100644 index 0000000..123ec2c --- /dev/null +++ b/oas-generator/pom.xml @@ -0,0 +1,64 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Licensed to the Apache Software Foundation (ASF) under one or more + ~ contributor license agreements. See the NOTICE file distributed with + ~ this work for additional information regarding copyright ownership. + ~ The ASF licenses this file to You under the Apache License, Version 2.0 + ~ (the "License"); you may not use this file except in compliance with + ~ the License. You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>toolkit</artifactId> + <groupId>org.apache.servicecomb.toolkit</groupId> + <version>0.2.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <packaging>pom</packaging> + <modules> + <module>oas-generator-core</module> + </modules> + + <artifactId>oas-generator</artifactId> + + <dependencies> + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-module-junit4</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>org.powermock</groupId> + <artifactId>powermock-api-mockito</artifactId> + <version>1.6.2</version> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.1</version> + <configuration> + <target>1.8</target> + <source>1.8</source> + </configuration> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file
