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 638b269d34cd9e7e4e4c1fcb2177be1b63a31f3a Author: kakulisen <[email protected]> AuthorDate: Mon Dec 23 11:45:44 2019 +0800 [SCB-1676] nested complex properties are not parsed and added to the component Signed-off-by: kakulisen <[email protected]> --- .../generator/annotation/ModelInterceptor.java | 4 +- .../toolkit/generator/util/ModelConverter.java | 60 ++++++- .../servicecomb/toolkit/generator/UtilsTest.java | 197 ++++++++++++++++++++- .../generator/MultipartFileInterceptor.java | 4 +- 4 files changed, 260 insertions(+), 5 deletions(-) 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 index 8415e1a..c6c8954 100644 --- 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 @@ -17,6 +17,8 @@ package org.apache.servicecomb.toolkit.generator.annotation; +import java.lang.reflect.Type; + import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.media.Schema; @@ -24,5 +26,5 @@ public interface ModelInterceptor { int order(); - Schema process(Class<?> cls, Components components); + Schema process(Type cls, Components components); } 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 index 307863d..ae3f9e4 100644 --- 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 @@ -17,10 +17,16 @@ package org.apache.servicecomb.toolkit.generator.util; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.ServiceLoader; import org.apache.servicecomb.toolkit.generator.annotation.ModelInterceptor; @@ -37,6 +43,7 @@ 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.ObjectSchema; import io.swagger.v3.oas.models.media.Schema; public class ModelConverter { @@ -64,11 +71,11 @@ public class ModelConverter { interceptorMgr.remove(interceptor); } - public static Schema getSchema(Class<?> cls) { + public static Schema getSchema(Type cls) { return getSchema(cls, null); } - public static Schema getSchema(Class<?> cls, Components components) { + public static Schema getSchema(Type cls, Components components) { for (ModelInterceptor interceptor : interceptorMgr) { Schema schema = interceptor.process(cls, components); @@ -77,16 +84,42 @@ public class ModelConverter { } } + if (cls instanceof Class) { + Map<String, Type> beanProperties = getBeanProperties((Class) cls); + + Optional.ofNullable(beanProperties) + .ifPresent(properties -> properties.forEach((name, type) -> + { + if (type instanceof ParameterizedType) { + Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); + Arrays.stream(actualTypeArguments).forEach(arg -> getSchema(arg, components)); + } + + if (type instanceof Class) { + getSchema(type, components); + } + }) + ); + } + Schema schema = PrimitiveType.createProperty(cls); if (schema == null) { schema = context .resolve(new AnnotatedType(cls)); } + if (schema == null) { + if (cls == List.class) { + schema = new ArraySchema(); + ((ArraySchema) schema).setItems(new ObjectSchema()); + } + } + if (components == null) { return schema; } + // correct reference Schema refSchema = schema; if (shouldExtractRef(schema)) { @@ -143,4 +176,27 @@ public class ModelConverter { return mapper; } + + public static Map<String, Type> getBeanProperties(Class cls) { + if (cls.isPrimitive()) { + return null; + } + Method[] declaredMethods = cls.getDeclaredMethods(); + Map<String, Type> beanProperties = new HashMap<>(); + + for (Method method : declaredMethods) { + if (method.getName().startsWith("get")) { + if (method.getReturnType() != null && method.getReturnType() != void.class) { + String propName = method.getName().substring(3); + try { + cls.getDeclaredMethod("set" + propName, method.getReturnType()); + beanProperties.put(method.getName(), method.getGenericReturnType()); + } catch (NoSuchMethodException e) { + continue; + } + } + } + } + return beanProperties; + } } 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 index 1ef65d1..6aab6b9 100644 --- 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 @@ -21,6 +21,7 @@ import static org.mockito.Mockito.when; import java.lang.reflect.Method; import java.lang.reflect.Parameter; +import java.lang.reflect.Type; import java.util.List; import org.apache.servicecomb.toolkit.generator.annotation.ModelInterceptor; @@ -74,7 +75,7 @@ public class UtilsTest { } @Override - public Schema process(Class<?> cls, Components components) { + public Schema process(Type cls, Components components) { return new Schema().name("unknown"); } }; @@ -83,6 +84,55 @@ public class UtilsTest { schema = ModelConverter.getSchema(ParameterClass.class); Assert.assertEquals("unknown", schema.getName()); ModelConverter.unRegisterInterceptor(mockModelInterceptor); + + Components component = new Components(); + ModelConverter.getSchema(BeanClass.class, component); + Assert.assertNotNull(component.getSchemas().get("Value")); + + Schema beanClass = component.getSchemas().get("BeanClass"); + Assert.assertNotNull(beanClass); + Schema valueRef = (Schema) beanClass.getProperties().get("value"); + Assert.assertEquals("#/components/schemas/Value", valueRef.get$ref()); + + Schema intVal = (Schema) beanClass.getProperties().get("intVal"); + Assert.assertEquals("int32", intVal.getFormat()); + Assert.assertEquals("integer", intVal.getType()); + + Schema intObj = (Schema) beanClass.getProperties().get("intObj"); + Assert.assertEquals("int32", intObj.getFormat()); + Assert.assertEquals("integer", intObj.getType()); + + Schema longVal = (Schema) beanClass.getProperties().get("longVal"); + Assert.assertEquals("int64", longVal.getFormat()); + Assert.assertEquals("integer", longVal.getType()); + + Schema longObj = (Schema) beanClass.getProperties().get("longObj"); + Assert.assertEquals("int64", longObj.getFormat()); + Assert.assertEquals("integer", longObj.getType()); + + Schema doubleVal = (Schema) beanClass.getProperties().get("doubleVal"); + Assert.assertEquals("double", doubleVal.getFormat()); + Assert.assertEquals("number", doubleVal.getType()); + + Schema doubleObj = (Schema) beanClass.getProperties().get("doubleObj"); + Assert.assertEquals("double", doubleObj.getFormat()); + Assert.assertEquals("number", doubleObj.getType()); + + Schema props = (Schema) beanClass.getProperties().get("props"); + Assert.assertEquals(ArraySchema.class, props.getClass()); + Assert.assertEquals("array", props.getType()); + Assert.assertEquals("string", ((ArraySchema) props).getItems().getType()); + + Schema numbers = (Schema) beanClass.getProperties().get("numbers"); + Assert.assertEquals(ArraySchema.class, numbers.getClass()); + Assert.assertEquals("array", numbers.getType()); + Assert.assertEquals("integer", ((ArraySchema) numbers).getItems().getType()); + Assert.assertEquals("int32", ((ArraySchema) numbers).getItems().getFormat()); + + Schema values = (Schema) beanClass.getProperties().get("values"); + Assert.assertEquals(ArraySchema.class, values.getClass()); + Assert.assertEquals("array", values.getType()); + Assert.assertEquals("#/components/schemas/Value", ((ArraySchema) values).getItems().get$ref()); } @Test @@ -99,4 +149,149 @@ public class UtilsTest { public void method(String param) { } } + + class BeanClass { + + private String name; + + private int intVal; + + private long longVal; + + private double doubleVal; + + private Integer intObj; + + private Long longObj; + + private Double doubleObj; + + private Value value; + + List<String> props; + + List<Integer> numbers; + + List<Value> values; + + List list; + + public List getList() { + return list; + } + + public void setList(List list) { + this.list = list; + } + + public int getIntVal() { + return intVal; + } + + public void setIntVal(int intVal) { + this.intVal = intVal; + } + + public long getLongVal() { + return longVal; + } + + public void setLongVal(long longVal) { + this.longVal = longVal; + } + + public double getDoubleVal() { + return doubleVal; + } + + public void setDoubleVal(double doubleVal) { + this.doubleVal = doubleVal; + } + + public Integer getIntObj() { + return intObj; + } + + public void setIntObj(Integer intObj) { + this.intObj = intObj; + } + + public Long getLongObj() { + return longObj; + } + + public void setLongObj(Long longObj) { + this.longObj = longObj; + } + + public Double getDoubleObj() { + return doubleObj; + } + + public void setDoubleObj(Double doubleObj) { + this.doubleObj = doubleObj; + } + + public List<Value> getValues() { + return values; + } + + public void setValues(List<Value> values) { + this.values = values; + } + + public List<Integer> getNumbers() { + return numbers; + } + + public void setNumbers(List<Integer> numbers) { + this.numbers = numbers; + } + + public List<String> getProps() { + return props; + } + + public void setProps(List<String> props) { + this.props = props; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Value getValue() { + return value; + } + + public void setValue(Value value) { + this.value = value; + } + } + + class Value { + private String prop1; + + private String prop2; + + public String getProp1() { + return prop1; + } + + public void setProp1(String prop1) { + this.prop1 = prop1; + } + + public String getProp2() { + return prop2; + } + + public void setProp2(String prop2) { + this.prop2 = prop2; + } + } } diff --git a/oas-generator/oas-generator-spring/src/main/java/org/apache/servicecomb/toolkit/generator/MultipartFileInterceptor.java b/oas-generator/oas-generator-spring/src/main/java/org/apache/servicecomb/toolkit/generator/MultipartFileInterceptor.java index 4857143..a5c2a92 100644 --- a/oas-generator/oas-generator-spring/src/main/java/org/apache/servicecomb/toolkit/generator/MultipartFileInterceptor.java +++ b/oas-generator/oas-generator-spring/src/main/java/org/apache/servicecomb/toolkit/generator/MultipartFileInterceptor.java @@ -17,6 +17,8 @@ package org.apache.servicecomb.toolkit.generator; +import java.lang.reflect.Type; + import org.apache.servicecomb.toolkit.generator.annotation.ModelInterceptor; import org.apache.servicecomb.toolkit.generator.util.ModelConverter; import org.springframework.web.multipart.MultipartFile; @@ -33,7 +35,7 @@ public class MultipartFileInterceptor implements ModelInterceptor { } @Override - public Schema process(Class<?> cls, Components components) { + public Schema process(Type cls, Components components) { if (!MultipartFile.class.equals(cls)) { return null;
