You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2021/02/04 06:55:09 UTC

[dubbo-spi-extensions] 34/47: fix #10 中的问题 fix #7 增加BigDecimal, BigInteger的支持

This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch 2.7.x
in repository https://gitbox.apache.org/repos/asf/dubbo-spi-extensions.git

commit 9efb793dd333143a93f437a49ab9cc581de21052
Author: qq213539 <21...@qq.com>
AuthorDate: Fri Jan 29 18:19:22 2021 +0800

    fix #10 中的问题
    fix #7 增加BigDecimal, BigInteger的支持
---
 .../apache/dubbo/apidocs/annotations/ApiDoc.java   |   1 +
 .../dubbo/apidocs/annotations/ApiModule.java       |   1 +
 .../core/DubboApiDocsAnnotationScanner.java        | 111 +++++++++++++--------
 .../core/providers/DubboDocProviderImpl.java       |   4 -
 .../apache/dubbo/apidocs/utils/ClassTypeUtil.java  |  41 +++++---
 .../apidocs/examples/api/IQuickStartDemo.java      |  21 +++-
 .../examples/params/QuickStartRequestBase.java     |   4 +-
 .../examples/params/QuickStartRequestBean.java     |   4 +-
 ...equestBean.java => QuickStartRequestBean2.java} |  39 ++++----
 .../examples/params/QuickStartRespBean.java        |   4 +-
 .../examples/api/impl/QuickStartDemoImpl.java      |  32 ++++--
 .../src/main/resources/application.yml             |   5 +-
 12 files changed, 172 insertions(+), 95 deletions(-)

diff --git a/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiDoc.java b/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiDoc.java
index 6417f4d..7f0aafb 100644
--- a/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiDoc.java
+++ b/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiDoc.java
@@ -43,6 +43,7 @@ public @interface ApiDoc {
     /**
      * api version.
      */
+    @Deprecated
     String version() default "";
 
     /**
diff --git a/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiModule.java b/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiModule.java
index 0f97eaa..d3f6f29 100644
--- a/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiModule.java
+++ b/dubbo-api-docs/dubbo-api-docs-annotations/src/main/java/org/apache/dubbo/apidocs/annotations/ApiModule.java
@@ -43,6 +43,7 @@ public @interface ApiModule {
     /**
      * module version
      */
+    @Deprecated
     String version() default "";
 
 }
diff --git a/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/DubboApiDocsAnnotationScanner.java b/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/DubboApiDocsAnnotationScanner.java
index e8a8565..5878d3c 100644
--- a/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/DubboApiDocsAnnotationScanner.java
+++ b/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/DubboApiDocsAnnotationScanner.java
@@ -51,6 +51,8 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Parameter;
 import java.lang.reflect.Type;
 import java.lang.reflect.TypeVariable;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -100,13 +102,17 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
                 return;
             }
             boolean async;
+            String apiVersion;
             if (apiModuleClass.isAnnotationPresent(Service.class)) {
                 Service dubboService = apiModuleClass.getAnnotation(Service.class);
                 async = dubboService.async();
+                apiVersion = dubboService.version();
             } else {
                 DubboService dubboService = apiModuleClass.getAnnotation(DubboService.class);
                 async = dubboService.async();
+                apiVersion = dubboService.version();
             }
+            apiVersion = applicationContext.getEnvironment().resolvePlaceholders(apiVersion);
             ModuleCacheItem moduleCacheItem = new ModuleCacheItem();
             DubboApiDocsCache.addApiModule(moduleAnn.apiInterface().getCanonicalName(), moduleCacheItem);
             //module name
@@ -114,7 +120,7 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
             //interface name containing package path
             moduleCacheItem.setModuleClassName(moduleAnn.apiInterface().getCanonicalName());
             //module version
-            moduleCacheItem.setModuleVersion(moduleAnn.version());
+            moduleCacheItem.setModuleVersion(apiVersion);
 
             Method[] apiModuleMethods = apiModuleClass.getMethods();
             // API basic information list in module cache
@@ -122,7 +128,7 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
             moduleCacheItem.setModuleApiList(moduleApiList);
             for (Method method : apiModuleMethods) {
                 if (method.isAnnotationPresent(ApiDoc.class)) {
-                    processApiDocAnnotation(method, moduleApiList, moduleAnn, async, moduleCacheItem);
+                    processApiDocAnnotation(method, moduleApiList, moduleAnn, async, moduleCacheItem, apiVersion);
                 }
             }
         });
@@ -130,7 +136,7 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
     }
 
     private void processApiDocAnnotation(Method method, List<ApiCacheItem> moduleApiList, ApiModule moduleAnn,
-                                         boolean async, ModuleCacheItem moduleCacheItem) {
+                                         boolean async, ModuleCacheItem moduleCacheItem, String apiVersion) {
 
         ApiDoc dubboApi = method.getAnnotation(ApiDoc.class);
 
@@ -144,7 +150,7 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
         // API description
         apiListItem.setDescription(dubboApi.description());
         //API version
-        apiListItem.setApiVersion(dubboApi.version());
+        apiListItem.setApiVersion(apiVersion);
         //Description of API return data
         apiListItem.setApiRespDec(dubboApi.responseClassDescription());
 
@@ -161,7 +167,7 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
         apiParamsAndResp.setAsync(async);
         apiParamsAndResp.setApiName(method.getName());
         apiParamsAndResp.setApiDocName(dubboApi.value());
-        apiParamsAndResp.setApiVersion(dubboApi.version());
+        apiParamsAndResp.setApiVersion(apiVersion);
         apiParamsAndResp.setApiRespDec(dubboApi.responseClassDescription());
         apiParamsAndResp.setDescription(dubboApi.description());
         apiParamsAndResp.setApiModelClass(moduleCacheItem.getModuleClassName());
@@ -188,15 +194,15 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
                 }
             }
             ParamBean paramBean = this.processHtmlType(argClass, requestParam, null);
+            Parameter methodParameter = parameters[i];
             if (paramBean == null) {
                 // Not a basic type, handling properties in method parameters
-                List<ParamBean> apiParamsList = processField(argClass, parameterType);
+                List<ParamBean> apiParamsList = processField(argClass, parameterType, methodParameter);
                 if (apiParamsList != null && !apiParamsList.isEmpty()) {
                     paramListItem.setParamInfo(apiParamsList);
                 }
             } else {
                 // Is the basic type
-                Parameter methodParameter = parameters[i];
                 paramListItem.setName(methodParameter.getName());
                 paramListItem.setHtmlType(paramBean.getHtmlType().name());
                 paramListItem.setAllowableValues(paramBean.getAllowableValues());
@@ -219,7 +225,7 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
      * For the attributes in the method parameters, only one layer is processed.
      * The deeper layer is directly converted to JSON, and the deeper layer is up to 5 layers
      */
-    private List<ParamBean> processField(Class<?> argClass, Type parameterType) {
+    private List<ParamBean> processField(Class<?> argClass, Type parameterType, Parameter parameter) {
         Map<String, String> genericTypeAndNamesMap;
         if (parameterType instanceof ParameterizedTypeImpl) {
             ParameterizedTypeImpl parameterTypeImpl = (ParameterizedTypeImpl) parameterType;
@@ -227,8 +233,7 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
             Type[] actualTypeArguments = parameterTypeImpl.getActualTypeArguments();
             genericTypeAndNamesMap =  new HashMap<>(typeVariables.length);
             for (int i = 0; i < typeVariables.length; i++) {
-                TypeVariable<? extends Class<?>> typeVariable = typeVariables[i];
-                genericTypeAndNamesMap.put(typeVariable.getTypeName(), actualTypeArguments[i].getTypeName());
+                genericTypeAndNamesMap.put(typeVariables[i].getTypeName(), actualTypeArguments[i].getTypeName());
             }
         } else {
             genericTypeAndNamesMap =  new HashMap<>(0);
@@ -237,25 +242,59 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
         List<ParamBean> apiParamsList = new ArrayList(16);
         // get all fields
         List<Field> allFields = ClassTypeUtil.getAllFields(null, argClass);
-        for (Field field : allFields) {
-            ParamBean paramBean = new ParamBean();
-            paramBean.setName(field.getName());
-            String genericTypeName = genericTypeAndNamesMap.get(field.getGenericType().getTypeName());
-            Class<?> genericType = null;
-            if (StringUtils.isBlank(genericTypeName)) {
-                paramBean.setJavaType(field.getType().getCanonicalName());
-            } else {
-                paramBean.setJavaType(genericTypeName);
-                try {
-                    genericType = Class.forName(genericTypeName);
-                } catch (ClassNotFoundException e) {
-                    e.printStackTrace();
+        if (allFields.size() > 0) {
+            for (Field field : allFields) {
+                if ("serialVersionUID".equals(field.getName())) {
+                    continue;
+                }
+                ParamBean paramBean = new ParamBean();
+                paramBean.setName(field.getName());
+                String genericTypeName = genericTypeAndNamesMap.get(field.getGenericType().getTypeName());
+                Class<?> genericType = null;
+                if (StringUtils.isBlank(genericTypeName)) {
+                    paramBean.setJavaType(field.getType().getCanonicalName());
+                } else {
+                    paramBean.setJavaType(genericTypeName);
+                    genericType =ClassTypeUtil.makeClass(genericTypeName);
+                }
+                RequestParam requestParam = null;
+                if (field.isAnnotationPresent(RequestParam.class)) {
+                    // Handling @RequestParam annotations on properties
+                    requestParam = field.getAnnotation(RequestParam.class);
+                    paramBean.setDocName(requestParam.value());
+                    paramBean.setRequired(requestParam.required());
+                    paramBean.setDescription(requestParam.description());
+                    paramBean.setExample(requestParam.example());
+                    paramBean.setDefaultValue(requestParam.defaultValue());
+                } else {
+                    paramBean.setRequired(false);
+                }
+
+                if (this.processHtmlType(null == genericType ? field.getType() : genericType, requestParam, paramBean) == null) {
+                    // Not a basic type, handle as JSON
+                    Object objResult;
+                    if (null == genericType) {
+                        objResult = ClassTypeUtil.initClassTypeWithDefaultValue(
+                                field.getGenericType(), field.getType(), 0);
+                    } else {
+                        objResult = ClassTypeUtil.initClassTypeWithDefaultValue(
+                                null, genericType, 0, true);
+                    }
+                    if (!ClassTypeUtil.isBaseType(objResult)) {
+                        paramBean.setHtmlType(HtmlTypeEnum.TEXT_AREA);
+                        paramBean.setSubParamsJson(JSON.toJSONString(objResult, ClassTypeUtil.FAST_JSON_FEATURES));
+                    }
                 }
+                apiParamsList.add(paramBean);
             }
+        } else {
+            ParamBean paramBean = new ParamBean();
+            paramBean.setName(parameter.getName());
+            paramBean.setJavaType(argClass.getCanonicalName());
             RequestParam requestParam = null;
-            if (field.isAnnotationPresent(RequestParam.class)) {
+            if (parameter.isAnnotationPresent(RequestParam.class)) {
                 // Handling @RequestParam annotations on properties
-                requestParam = field.getAnnotation(RequestParam.class);
+                requestParam = parameter.getAnnotation(RequestParam.class);
                 paramBean.setDocName(requestParam.value());
                 paramBean.setRequired(requestParam.required());
                 paramBean.setDescription(requestParam.description());
@@ -265,20 +304,11 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
                 paramBean.setRequired(false);
             }
 
-            if (this.processHtmlType(null == genericType ? field.getType() : genericType, requestParam, paramBean) == null) {
-                // Not a basic type, handle as JSON
-                Object objResult;
-                if (null == genericType) {
-                    objResult =ClassTypeUtil.initClassTypeWithDefaultValue(
-                            field.getGenericType(), field.getType(), 0);
-                } else {
-                    objResult =ClassTypeUtil.initClassTypeWithDefaultValue(
-                            null, genericType, 0, true);
-                }
-                if (!ClassTypeUtil.isBaseType(objResult)) {
-                    paramBean.setHtmlType(HtmlTypeEnum.TEXT_AREA);
-                    paramBean.setSubParamsJson(JSON.toJSONString(objResult, ClassTypeUtil.FAST_JSON_FEATURES));
-                }
+            Object objResult = ClassTypeUtil.initClassTypeWithDefaultValue(
+                    parameterType, argClass, 0);
+            if (!ClassTypeUtil.isBaseType(objResult)) {
+                paramBean.setHtmlType(HtmlTypeEnum.TEXT_AREA);
+                paramBean.setSubParamsJson(JSON.toJSONString(objResult, ClassTypeUtil.FAST_JSON_FEATURES));
             }
             apiParamsList.add(paramBean);
         }
@@ -310,7 +340,8 @@ public class DubboApiDocsAnnotationScanner implements ApplicationListener<Applic
         } else if (Byte.class.isAssignableFrom(classType) || byte.class.isAssignableFrom(classType)) {
             param.setHtmlType(HtmlTypeEnum.TEXT_BYTE);
             processed = true;
-        } else if (Long.class.isAssignableFrom(classType) || long.class.isAssignableFrom(classType)) {
+        } else if (Long.class.isAssignableFrom(classType) || long.class.isAssignableFrom(classType) ||
+                BigDecimal.class.isAssignableFrom(classType) || BigInteger.class.isAssignableFrom(classType)) {
             param.setHtmlType(HtmlTypeEnum.NUMBER_INTEGER);
             processed = true;
         } else if (Double.class.isAssignableFrom(classType) || double.class.isAssignableFrom(classType)) {
diff --git a/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/providers/DubboDocProviderImpl.java b/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/providers/DubboDocProviderImpl.java
index 0bddd1c..a77bc91 100644
--- a/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/providers/DubboDocProviderImpl.java
+++ b/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/core/providers/DubboDocProviderImpl.java
@@ -18,16 +18,12 @@ package org.apache.dubbo.apidocs.core.providers;
 
 import org.apache.dubbo.apidocs.core.DubboApiDocsCache;
 import org.apache.dubbo.apidocs.core.beans.ModuleCacheItem;
-import org.apache.dubbo.common.logger.Logger;
-import org.apache.dubbo.common.logger.LoggerFactory;
-import org.apache.dubbo.config.annotation.DubboService;
 
 import java.util.List;
 
 /**
  * The api implementation of Dubbo doc.
  */
-@DubboService
 public class DubboDocProviderImpl implements IDubboDocProvider {
 
     @Override
diff --git a/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/utils/ClassTypeUtil.java b/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/utils/ClassTypeUtil.java
index 559f288..2efacd5 100644
--- a/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/utils/ClassTypeUtil.java
+++ b/dubbo-api-docs/dubbo-api-docs-core/src/main/java/org/apache/dubbo/apidocs/utils/ClassTypeUtil.java
@@ -22,6 +22,8 @@ import org.apache.commons.lang3.StringUtils;
 import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
 
 import java.lang.reflect.*;
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.*;
@@ -103,6 +105,19 @@ public class ClassTypeUtil {
             return initResult;
         }
 
+        Map<String, String> genericTypeAndNamesMap;
+        if (genericType instanceof ParameterizedTypeImpl) {
+            ParameterizedTypeImpl parameterTypeImpl = (ParameterizedTypeImpl) genericType;
+            TypeVariable<? extends Class<?>>[] typeVariables = parameterTypeImpl.getRawType().getTypeParameters();
+            Type[] actualTypeArguments = parameterTypeImpl.getActualTypeArguments();
+            genericTypeAndNamesMap =  new HashMap<>(typeVariables.length);
+            for (int i = 0; i < typeVariables.length; i++) {
+                genericTypeAndNamesMap.put(typeVariables[i].getTypeName(), actualTypeArguments[i].getTypeName());
+            }
+        } else {
+            genericTypeAndNamesMap =  new HashMap<>(0);
+        }
+
         Map<String, Object> result = new HashMap<>(16);
         if (isBuildClassAttribute) {
             result.put("class", classType.getCanonicalName());
@@ -130,23 +145,11 @@ public class ClassTypeUtil {
                 }
             } else {
                 // Check if the type of the property is generic
-                if ("T".equals(field2.getGenericType().getTypeName())) {
+                String genericTypeName = genericTypeAndNamesMap.get(field2.getGenericType().getTypeName());
+                if (StringUtils.isNotBlank(genericTypeName)) {
                     // The type of the attribute is generic. Find the generic from the definition of
                     // the class in which the attribute is located
-                    ParameterizedType pt = (ParameterizedType) genericType;
-                    Type[] actualTypeArguments = pt.getActualTypeArguments();
-                    if (actualTypeArguments.length > 0) {
-                        if (actualTypeArguments.length == 1) {
-                            result.put(field2.getName(), initClassTypeWithDefaultValue(
-                                    makeParameterizedType(actualTypeArguments[0].getTypeName()),
-                                    makeClass(pt.getActualTypeArguments()[0].getTypeName()), processCount));
-                        } else {
-                            LOG.warn(classType.getName() + "#" + field2.getName() + " generics are not supported temporarily. " +
-                                    "This property will be ignored");
-                        }
-                    } else {
-                        result.put(field2.getName(), initClassTypeWithDefaultValue(field2.getGenericType(), field2.getType(), processCount));
-                    }
+                    result.put(field2.getName(), initClassTypeWithDefaultValue(null, makeClass(genericTypeName), processCount, true));
                 } else {
                     // Not generic
                     result.put(field2.getName(), initClassTypeWithDefaultValue(field2.getGenericType(), field2.getType(), processCount));
@@ -232,6 +235,10 @@ public class ClassTypeUtil {
             ParameterizedType pt = (ParameterizedType) genericType;
             String typeName = pt.getActualTypeArguments()[0].getTypeName();
             return initClassTypeWithDefaultValue(makeParameterizedType(typeName), makeClass(typeName), processCount);
+        } else if (BigDecimal.class.isAssignableFrom(classType)) {
+            return 0;
+        } else if (BigInteger.class.isAssignableFrom(classType)) {
+            return 0;
         }
         return null;
     }
@@ -251,7 +258,9 @@ public class ClassTypeUtil {
                 o instanceof Character ||
                 o instanceof Short ||
                 o instanceof Boolean ||
-                o instanceof String) {
+                o instanceof String ||
+                o instanceof BigDecimal ||
+                o instanceof BigInteger) {
             return true;
         }
         return false;
diff --git a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/api/IQuickStartDemo.java b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/api/IQuickStartDemo.java
index aa5251e..c3bca6f 100644
--- a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/api/IQuickStartDemo.java
+++ b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/api/IQuickStartDemo.java
@@ -19,9 +19,12 @@ package org.apache.dubbo.apidocs.examples.api;
 import org.apache.dubbo.apidocs.examples.params.DemoParamBean4;
 import org.apache.dubbo.apidocs.examples.params.QuickStartRequestBase;
 import org.apache.dubbo.apidocs.examples.params.QuickStartRequestBean;
+import org.apache.dubbo.apidocs.examples.params.QuickStartRequestBean2;
 import org.apache.dubbo.apidocs.examples.params.QuickStartRespBean;
 
+import java.math.BigDecimal;
 import java.util.List;
+import java.util.Map;
 
 /**
  * quick start demo.
@@ -35,14 +38,26 @@ public interface IQuickStartDemo {
      * @param beanParam
      * @return org.apache.dubbo.apidocs.examples.params.QuickStartRespBean
      */
-//    QuickStartRespBean quickStart(String strParam, QuickStartRequestBean beanParam);
+//    QuickStartRespBean quickStart(List<DemoParamBean4> strParam, QuickStartRequestBean beanParam);
 
     /**
-     * quick start demo, request use generic.
+     * quick start demo2, request use generic.
      * @param beanList
      * @param beanParam
      * @return org.apache.dubbo.apidocs.examples.params.QuickStartRespBean
      */
-    QuickStartRespBean quickStart2(List<String> beanList, QuickStartRequestBase<QuickStartRequestBean, DemoParamBean4> beanParam);
+//    QuickStartRespBean quickStart2(Map<String, DemoParamBean4> beanList, QuickStartRequestBase<QuickStartRequestBean, DemoParamBean4> beanParam);
 
+    /**
+     * quick start demo3, request use multiple generic.
+     * @return org.apache.dubbo.apidocs.examples.params.QuickStartRespBean
+     */
+//    QuickStartRespBean quickStart3(QuickStartRequestBean2 beanParam);
+
+    /**
+     * quick start demo4, response use multiple generic bean, but not set generic.
+     * @param beanParam
+     * @return org.apache.dubbo.apidocs.examples.params.QuickStartRequestBase
+     */
+    QuickStartRequestBase quickStart4(BigDecimal number, QuickStartRequestBean2 beanParam);
 }
diff --git a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBase.java b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBase.java
index 94cbd0f..5453ca9 100644
--- a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBase.java
+++ b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBase.java
@@ -7,7 +7,9 @@ import org.apache.dubbo.apidocs.annotations.RequestParam;
  *
  * @date 2021/1/26 15:24
  */
-public class QuickStartRequestBase<E, T> {
+public class QuickStartRequestBase<E, T> implements java.io.Serializable {
+
+    private static final long serialVersionUID = 373497393757790262L;
 
     @RequestParam(value = "Request method", required = true)
     private String method;
diff --git a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean.java b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean.java
index 30e9ef3..1388efd 100644
--- a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean.java
+++ b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean.java
@@ -21,7 +21,9 @@ import org.apache.dubbo.apidocs.annotations.RequestParam;
 /**
  * quick start demo request parameter bean.
  */
-public class QuickStartRequestBean {
+public class QuickStartRequestBean implements java.io.Serializable {
+
+    private static final long serialVersionUID = -7214413446084107294L;
 
     @RequestParam(value = "You name", required = true, description = "please enter your full name", example = "Zhang San")
     private String name;
diff --git a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean.java b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean2.java
similarity index 59%
copy from dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean.java
copy to dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean2.java
index 30e9ef3..815cd10 100644
--- a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean.java
+++ b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRequestBean2.java
@@ -18,19 +18,23 @@ package org.apache.dubbo.apidocs.examples.params;
 
 import org.apache.dubbo.apidocs.annotations.RequestParam;
 
+import java.math.BigDecimal;
+
 /**
  * quick start demo request parameter bean.
  */
-public class QuickStartRequestBean {
+public class QuickStartRequestBean2 implements java.io.Serializable {
+
+    private static final long serialVersionUID = -7214413446084107294L;
 
     @RequestParam(value = "You name", required = true, description = "please enter your full name", example = "Zhang San")
     private String name;
 
-    @RequestParam(value = "You age", defaultValue = "18")
-    private int age;
+    @RequestParam(value = "multiple generic")
+    private QuickStartRequestBase<QuickStartRequestBean, DemoParamBean4> requestBase;
 
-    @RequestParam("Are you a main?")
-    private boolean man;
+    @RequestParam(value = "BigDecimal number")
+    private BigDecimal bigDecimalNumber;
 
     public String getName() {
         return name;
@@ -40,28 +44,19 @@ public class QuickStartRequestBean {
         this.name = name;
     }
 
-    public int getAge() {
-        return age;
-    }
-
-    public void setAge(int age) {
-        this.age = age;
+    public QuickStartRequestBase<QuickStartRequestBean, DemoParamBean4> getRequestBase() {
+        return requestBase;
     }
 
-    public boolean getMan() {
-        return man;
+    public void setRequestBase(QuickStartRequestBase<QuickStartRequestBean, DemoParamBean4> requestBase) {
+        this.requestBase = requestBase;
     }
 
-    public void setMan(boolean man) {
-        this.man = man;
+    public BigDecimal getBigDecimalNumber() {
+        return bigDecimalNumber;
     }
 
-    @Override
-    public String toString() {
-        return "QuickStartRequestBean{" +
-                "name='" + name + '\'' +
-                ", age=" + age +
-                ", man=" + man +
-                '}';
+    public void setBigDecimalNumber(BigDecimal bigDecimalNumber) {
+        this.bigDecimalNumber = bigDecimalNumber;
     }
 }
diff --git a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRespBean.java b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRespBean.java
index ccb84c7..660a6a6 100644
--- a/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRespBean.java
+++ b/dubbo-api-docs/dubbo-api-docs-examples/examples-api/src/main/java/org/apache/dubbo/apidocs/examples/params/QuickStartRespBean.java
@@ -21,7 +21,9 @@ import org.apache.dubbo.apidocs.annotations.ResponseProperty;
 /**
  * quick star demo response bean.
  */
-public class QuickStartRespBean {
+public class QuickStartRespBean implements java.io.Serializable {
+
+    private static final long serialVersionUID = 7598240511561924368L;
 
     @ResponseProperty(value = "Response code", example = "500")
     private int code;
diff --git a/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/java/org/apache/dubbo/apidocs/examples/api/impl/QuickStartDemoImpl.java b/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/java/org/apache/dubbo/apidocs/examples/api/impl/QuickStartDemoImpl.java
index c2c9d17..f246c96 100644
--- a/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/java/org/apache/dubbo/apidocs/examples/api/impl/QuickStartDemoImpl.java
+++ b/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/java/org/apache/dubbo/apidocs/examples/api/impl/QuickStartDemoImpl.java
@@ -18,33 +18,53 @@ package org.apache.dubbo.apidocs.examples.api.impl;
 
 import org.apache.dubbo.apidocs.annotations.ApiDoc;
 import org.apache.dubbo.apidocs.annotations.ApiModule;
+import org.apache.dubbo.apidocs.annotations.RequestParam;
 import org.apache.dubbo.apidocs.examples.api.IQuickStartDemo;
 import org.apache.dubbo.apidocs.examples.params.DemoParamBean4;
 import org.apache.dubbo.apidocs.examples.params.QuickStartRequestBase;
 import org.apache.dubbo.apidocs.examples.params.QuickStartRequestBean;
+import org.apache.dubbo.apidocs.examples.params.QuickStartRequestBean2;
 import org.apache.dubbo.apidocs.examples.params.QuickStartRespBean;
 import org.apache.dubbo.config.annotation.DubboService;
 
+import java.math.BigDecimal;
 import java.util.List;
+import java.util.Map;
 
 /**
  * quick start demo implement.
  *
  * @date 2020/12/23 17:21
  */
-@DubboService(version = "v0.1")
-@ApiModule(value = "quick start demo", apiInterface = IQuickStartDemo.class, version = "v0.1")
+@DubboService(version = "${demo.apiversion.quickstart}")
+@ApiModule(value = "quick start demo", apiInterface = IQuickStartDemo.class)
 public class QuickStartDemoImpl implements IQuickStartDemo {
 
 //    @ApiDoc(value = "quick start demo", version = "v0.1", description = "this api is a quick start demo", responseClassDescription="A quick star response bean")
 //    @Override
-//    public QuickStartRespBean quickStart(@RequestParam(value = "strParam", required = true) String strParam, QuickStartRequestBean beanParam) {
+//    public QuickStartRespBean quickStart(@RequestParam(value = "strParamxxx", required = true) List<DemoParamBean4> strParam, QuickStartRequestBean beanParam) {
 //        return new QuickStartRespBean(200, "hello " + beanParam.getName() + ", " + beanParam.toString());
 //    }
+//
+//    @ApiDoc(value = "quick start demo, request use generic.", version = "v0.1", description = "quick start demo, request use generic.", responseClassDescription="A quick star response bean")
+//    @Override
+//    public QuickStartRespBean quickStart2(Map<String, DemoParamBean4> beanList, QuickStartRequestBase<QuickStartRequestBean, DemoParamBean4> beanParam) {
+//        return new QuickStartRespBean(200, "【" + beanParam.getMethod() + "】hello " + beanParam.getBody3() + ", " + beanParam.toString());
+//    }
+//
+//    @ApiDoc(value = "multiple generic demo", version = "v0.1", description = "multiple generic demo.", responseClassDescription="A quick star response bean")
+//    @Override
+//    public QuickStartRespBean quickStart3(QuickStartRequestBean2 beanParam) {
+//        return new QuickStartRespBean(200,"quickStart3, multiple generic demo");
+//    }
 
-    @ApiDoc(value = "quick start demo, request use generic.", version = "v0.1", description = "quick start demo, request use generic.", responseClassDescription="A quick star response bean")
+    @ApiDoc(value = "response use multiple generic bean", description = "response use multiple generic bean, but not set generic.", responseClassDescription="A quick star response bean")
     @Override
-    public QuickStartRespBean quickStart2(List<String> beanList, QuickStartRequestBase<QuickStartRequestBean, DemoParamBean4> beanParam) {
-        return new QuickStartRespBean(200, "【" + beanParam.getMethod() + "】hello " + beanParam.getBody3().getName() + ", " + beanParam.toString());
+    public QuickStartRequestBase quickStart4(BigDecimal number, QuickStartRequestBean2 beanParam) {
+        QuickStartRequestBase response = new QuickStartRequestBase();
+        response.setBody("body");
+        response.setBody3("body3");
+        response.setMethod("test");
+        return response;
     }
 }
diff --git a/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/resources/application.yml b/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/resources/application.yml
index ae4c2fa..2e8048a 100644
--- a/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/resources/application.yml
+++ b/dubbo-api-docs/dubbo-api-docs-examples/examples-provider/src/main/resources/application.yml
@@ -14,4 +14,7 @@ dubbo:
   application:
     name: dubbo-api-docs-example-provider
   metadata-report:
-    address: nacos://127.0.0.1:8848
\ No newline at end of file
+    address: nacos://127.0.0.1:8848
+demo:
+  apiversion:
+    quickstart: v0.1
\ No newline at end of file