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 <wuji...@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&lt;T1, T2&gt;
+ *    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
wuji...@apache.org.

Reply via email to