You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by wu...@apache.org on 2018/05/09 17:31:10 UTC
[incubator-servicecomb-java-chassis] 03/07: [SCB-538][WIP] create
SwaggerToClassGenerator
This is an automated email from the ASF dual-hosted git repository.
wujimin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-servicecomb-java-chassis.git
commit 2868fa3a092c89b33fb91233d0809cd72e873212
Author: wujimin <wu...@huawei.com>
AuthorDate: Fri May 4 00:27:23 2018 +0800
[SCB-538][WIP] create SwaggerToClassGenerator
---
.../swagger/converter/SwaggerToClassGenerator.java | 259 +++++++++++++++++++++
1 file changed, 259 insertions(+)
diff --git a/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/SwaggerToClassGenerator.java b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/SwaggerToClassGenerator.java
new file mode 100644
index 0000000..3205c02
--- /dev/null
+++ b/swagger/swagger-generator/generator-core/src/main/java/org/apache/servicecomb/swagger/converter/SwaggerToClassGenerator.java
@@ -0,0 +1,259 @@
+/*
+ * 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.swagger.converter;
+
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.servicecomb.common.javassist.ClassConfig;
+import org.apache.servicecomb.common.javassist.JavassistUtils;
+import org.apache.servicecomb.common.javassist.MethodConfig;
+import org.apache.servicecomb.swagger.generator.core.SwaggerConst;
+import org.apache.servicecomb.swagger.generator.core.utils.ClassUtils;
+import org.springframework.util.StringUtils;
+
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import com.google.common.annotations.VisibleForTesting;
+
+import io.swagger.models.Model;
+import io.swagger.models.Operation;
+import io.swagger.models.Path;
+import io.swagger.models.Response;
+import io.swagger.models.Swagger;
+import io.swagger.models.parameters.Parameter;
+import io.swagger.models.properties.Property;
+
+/**
+ * generate interface from swagger<br>
+ * specially should support:<br>
+ * <pre>
+ * 1. recursive dependency:
+ * 1). class A {
+ * A a;
+ * }
+ * 2). circular dependency:
+ * class A {
+ * B b;
+ * }
+ * class B {
+ * A a;
+ * }
+ * 2. CustomerGeneric<T1, T2>
+ * should generate 3 classes: CustomerGeneric/T1/T2
+ * this can avoid unnecessary convert between consumer/contract/producer
+ * </pre>
+ *
+ * javassist can create normal dynamic class to classloader<br>
+ * but can not create recursive dependency dynamic class to classloader directly<br>
+ * to support recursive dependency, must save all class to byte[], and then convert to class<br>
+ *
+ */
+public class SwaggerToClassGenerator {
+ private ClassLoader classLoader;
+
+ private Swagger swagger;
+
+ /**
+ * package for definitions that no x-java-class attribute
+ */
+ private String packageName;
+
+ /**
+ * if not set, then will get from swagger.info.vendorExtensions.x-java-interface
+ * if still not set, then will use ${packageName}.SchemaInterface
+ */
+ private String interfaceName;
+
+ private Class<?> interfaceCls;
+
+ private TypeFactory typeFactory;
+
+ // key is swagger model or property
+ @VisibleForTesting
+ protected Map<Object, JavaType> swaggerObjectMap = new IdentityHashMap<>();
+
+ /**
+ *
+ * @param classLoader
+ * @param swagger
+ * @param packageName package for definitions that no x-java-class attribute
+ */
+ public SwaggerToClassGenerator(ClassLoader classLoader, Swagger swagger, String packageName) {
+ this.classLoader = classLoader;
+ this.swagger = swagger;
+ this.packageName = packageName;
+
+ this.typeFactory = TypeFactory.defaultInstance().withClassLoader(classLoader);
+ }
+
+ public void setInterfaceName(String interfaceName) {
+ this.interfaceName = interfaceName;
+ }
+
+ public ClassLoader getClassLoader() {
+ return classLoader;
+ }
+
+ public Swagger getSwagger() {
+ return swagger;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public TypeFactory getTypeFactory() {
+ return typeFactory;
+ }
+
+ public Class<?> getInterfaceCls() {
+ return interfaceCls;
+ }
+
+ /**
+ * convert definitions/parameters and responses to java class
+ * convert swagger to interface
+ */
+ public Class<?> convert() {
+ collectInterfaceName();
+ mapDefinitionsToExistingClasses();
+ convertDefinitions();
+ convertResponses();
+ convertToInterface();
+
+ return interfaceCls;
+ }
+
+ protected void collectInterfaceName() {
+ if (interfaceName != null) {
+ return;
+ }
+
+ if (swagger.getInfo() != null) {
+ interfaceName = ClassUtils.getInterfaceName(swagger.getInfo().getVendorExtensions());
+ if (interfaceName != null) {
+ return;
+ }
+ }
+
+ interfaceName = packageName + ".SchemaInterface";
+ }
+
+ protected void mapDefinitionsToExistingClasses() {
+ interfaceCls = ClassUtils.getClassByName(classLoader, interfaceName);
+ if (interfaceCls == null) {
+ return;
+ }
+
+ // TODO: map
+ }
+
+ protected void convertDefinitions() {
+ if (swagger.getDefinitions() == null) {
+ return;
+ }
+
+ for (Entry<String, Model> entry : swagger.getDefinitions().entrySet()) {
+ convertModel(entry.getKey(), entry.getValue());
+ }
+ }
+
+ protected void convertResponses() {
+ if (swagger.getPaths() == null) {
+ return;
+ }
+
+ for (Path path : swagger.getPaths().values()) {
+ for (Operation operation : path.getOperations()) {
+ for (Response response : operation.getResponses().values()) {
+ convert(response.getSchema());
+
+ Map<String, Property> headers = response.getHeaders();
+ if (headers == null) {
+ continue;
+ }
+ for (Property header : headers.values()) {
+ convert(header);
+ }
+ }
+ }
+ }
+ }
+
+ protected void convertToInterface() {
+ if (interfaceCls != null) {
+ return;
+ }
+
+ ClassConfig classConfig = new ClassConfig();
+ classConfig.setClassName(interfaceName);
+ classConfig.setIntf(true);
+
+ if (swagger.getPaths() != null) {
+ for (Path path : swagger.getPaths().values()) {
+ for (Operation operation : path.getOperations()) {
+ Response result = operation.getResponses().get(SwaggerConst.SUCCESS_KEY);
+ JavaType resultJavaType = swaggerObjectMap.get(result.getSchema());
+
+ MethodConfig methodConfig = new MethodConfig();
+ methodConfig.setName(operation.getOperationId());
+ methodConfig.setResult(resultJavaType);
+
+ for (Parameter parameter : operation.getParameters()) {
+ String paramName = parameter.getName();
+ paramName = ClassUtils.correctMethodParameterName(paramName);
+
+ JavaType paramJavaType = ConverterMgr.findJavaType(this, parameter);
+ methodConfig.addParameter(paramName, paramJavaType);
+ }
+
+ classConfig.addMethod(methodConfig);
+ }
+ }
+ }
+
+ interfaceCls = JavassistUtils.createClass(classLoader, classConfig);
+ }
+
+ public JavaType convert(Object swaggerObject) {
+ JavaType javaType = swaggerObjectMap.get(swaggerObject);
+ if (javaType == null) {
+ javaType = ConverterMgr.findJavaType(this, swaggerObject);
+ swaggerObjectMap.put(swaggerObject, javaType);
+ }
+ return javaType;
+ }
+
+ protected void updateJavaClassInVendor(Map<String, Object> vendorExtensions, String shortClsName) {
+ String clsName = ClassUtils.getClassName(vendorExtensions);
+ if (StringUtils.isEmpty(clsName)) {
+ vendorExtensions.put(SwaggerConst.EXT_JAVA_CLASS, packageName + "." + shortClsName);
+ }
+ }
+
+ protected JavaType convertModel(String name, Model model) {
+ updateJavaClassInVendor(model.getVendorExtensions(), name);
+ return convert(model);
+ }
+
+ public JavaType convertRef(String ref) {
+ return convertModel(ref, swagger.getDefinitions().get(ref));
+ }
+}
--
To stop receiving notification emails like this one, please contact
wujimin@apache.org.