Android api 代码自动生成

863 阅读5分钟

android  api 自动生成基于Android gradle plugin,以及maven,接口基于swagger,该插件,生成的代码为 kotlin编程语言。生成的网诺接口使用OKhttp+retrofit

一 api 自动生成 gradle 插件

插件工程目录

1.1 gradle 文件配置

apply plugin: 'groovy'
apply plugin: 'maven'

dependencies {
    implementation gradleApi()
    implementation localGroovy()
}

repositories {
    mavenCentral()
}

group = 'com.yryz.plugin'
version = '1.0.0'
archivesBaseName = 'module-api-plugin'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: uri('../module_api_repository'))//本地仓库maven配置
        }
    }
}

1.2 配置 ApiModulePlugin 的META-IN  对应 com.yryz.plugin.properties 文件

implementation-class=com.yryz.plugin.ApiModulePlugin

1.3  自定义插件:ApiModulePlugin为插件入口文件,继承gradle Plugin, 自己定义一个apiTask 的gradle Task

package com.yryz.plugin

import org.gradle.api.Plugin
import org.gradle.api.Project

class ApiModulePlugin implements Plugin<Project> {

    @Override
    void apply(Project project) {
        println("ApiModulePlugin --apply")
        project.task("apiTask", type: ApiModuleTask)
    }
}

1.4 自定义Task :ApiModuleTask为自定义Task,继承gradle DefaultTask。

package com.yryz.plugin

import groovy.json.JsonSlurper
import org.gradle.api.DefaultTask
import org.gradle.api.tasks.TaskAction

class ApiModuleTask extends DefaultTask {

    @TaskAction
    void apiTask() {
        println("ApiModuleTask --apiTask 开始执行")
        def classList = new ArrayList<String>()
        def config = readerConfig()
        def api = config["api"]
        config["serviceName"].each {
            try {
                def apiDocsStr = "${api["baseUrl"]}/${it}/${api["version"]}"
                def apiGenerator = new ApiGenerator(it, apiDocsStr, config, classList)
                apiGenerator.generate()
            } catch (Exception e) {
                def message = "ApiModuleTask 解析出错  ${e.message}"
                println(message)
            }

        }
    }
    //解析配置文件,得到需要生成api服务地址,以及其他扩展信息,文件配置在依赖工程的目录下面
    private Object readerConfig() {
        def file = new File("./apiConfig.json")
        def jsonSlurper = new JsonSlurper()
        return jsonSlurper.parse(file)
    }

}

1.5 api 生成的逻辑,就是对 JSON 的解析,生成对应的api文件,实体文件。

package com.yryz.plugin

import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.codehaus.groovy.runtime.ResourceGroovyMethods

class ApiGenerator {

    private def spaces = "        "
    private def spacesInterface = "    "
    private def spacesInterfaceDouble = "        "

    private def serviceName

    private def apiDocsStr

    private Map apiPaths = new HashMap()

    private Map<String, TsType> typeDefinitionMap = new HashMap()

    private Object apiDocs

    private List<String> configList

    private Map<String, Object> customMap

    private List<String> classList

    ApiGenerator(String serviceName, String apiDocsStr, Object config, List<String> classList) {
        this.serviceName = serviceName
        this.apiDocsStr = apiDocsStr
        this.classList = classList
        this.configList = config["serializable"] ?: new ArrayList()
        this.customMap = config["custom"] ?: new HashMap()

    }

    public void generate() {

        //根据网诺 url 获取对应的api 实体map
        def jsonSlurper = new JsonSlurper()
        def apiDocsUrl = new URL(apiDocsStr)
        def map = jsonSlurper.parse(apiDocsUrl, "utf-8")
        this.apiDocs = map
        def paths = map["paths"]
        paths.each {

            String path = it.key
            def pathInfo = it.value
            if (!path
                    || !path.contains('/{version}/')
                    || path.contains('/pv/')
                    || path.contains('/pvs/')
                    || path.contains('pb/images/action/download')) {
                return true
            }
            def url = path.replace('/{version}/', "/[api_version]/")
            def pathParts = url.split('/')
             println "##### ${url} "
            pathInfo.each {
                def httpMethod = it.key
                def httpMethodVlue = it.value

                def produces = httpMethodVlue["produces"]
                if (produces instanceof ArrayList) {
                    if (produces.size() && produces[0] == "application/octet-stream") {
                        return true
                    }
                }
                def tags = httpMethodVlue["tags"]
                if (tags instanceof ArrayList) {
                    if (tags.contains("ignore")) {
                        return true
                    }
                }
                def className = ""
                if (path.contains('/action/')) {
                    className = pathParts[pathParts.length - 3]
                } else if (pathParts[pathParts.length - 1].contains('{')) {
                    className = pathParts[pathParts.length - 2]
                } else {
                    className = pathParts[pathParts.length - 1]
                }
                className = transformCamelCase(className)
                if (className == 'geetest') {
                    return true
                }
                apiPaths[className] = apiPaths[className] ?: new HashMap()

                def responses = httpMethodVlue["responses"]
                def responseOk = responses["200"]
                try {
                    def ref = responseOk["schema"]["\$ref"]
                    // def ref = responseOk["schema"]['$ref']
                    if (!ref || ref.indexOf('Response«') < 0) {
                        throw new Exception("接口返回类型出错")
                    }
                    def typeName = getType(responseOk)

                    def methodName = path.contains('/action/') ? transformCamelCase(pathParts[pathParts.length - 1]) : httpMethod
                    if (apiPaths[className][methodName]) {
                        def jsonOutput = new JsonOutput()
                        def result = jsonOutput.toJson(apiPaths[className][methodName])
                        def message = "解析出相同的方法名 ${result},${path}"
                        throw new Exception(message)
                    }

                    def parameters = httpMethodVlue["parameters"]
                    parameters.each {
                        it["typeName"] = getType(it)
                    }
                    def summary = httpMethodVlue["summary"]

                    def hashMap = new HashMap<>()

                    hashMap["className"] = className

                    hashMap["typeName"] = typeName

                    hashMap["url"] = url
                    hashMap["method"] = httpMethod
                    hashMap["parameters"] = parameters
                    hashMap["summary"] = summary

                    apiPaths[className][methodName] = hashMap
                } catch (Exception e) {
                    def jsonOutput = new JsonOutput()
                    def result = jsonOutput.toJson(responseOk)
                    def message = "解析出错 ${e.class.simpleName} ${e.message} ${serviceName} path:${path} responseSchema:${result}"
                    // throw `${ex}${this.serviceName} path:${path} responseSchema:${JSON.stringify(responseOk)}`
                    throw new Exception(message)
                }
            }
        }
        this.generateFile()
    }

    private String transformCamelCase(String str) {
        String[] array = str.split("-")
        String result = ""
        for (int i = 0; i < array.length; i++) {
            def indexValue = array[i]
            if (i != 0) {
                def index0 = indexValue.substring(0, 1)
                indexValue = indexValue.replace(index0, index0.toUpperCase())
            }
            result += indexValue
        }
        return result
    }

    private String getType(Object property) {
        return getType(property, null)
    }

    private String getType(Object property, Object ref) {

        if (property instanceof String) {
            def refType = property.replace('#/definitions/', '')
            if (refType.contains('Response«')) {
                refType = refType.replace('Response«', '').replaceFirst('»', '')
            }
            def typeName = this.getRefType(refType, ref)
            return typeName
        }

        def type = property["type"]
        def schema = property["schema"]
        //def $ref = property['$ref']
        def $ref = property["\$ref"]
        def format = property['format']
        if ($ref) {
            def returnRef = getType($ref, property)
            return returnRef
        }
        if (schema) {
            def returnSchema = getType(schema, ref)
            return returnSchema
        }

        switch (type) {
            case 'int':
            case 'int32':
            case 'integer':
            case 'number':
                if (format == "int64") {
                    return "Long"
                }
                if (format == "double") {
                    return "Double"
                }
                if (format == "float") {
                    return "Float"
                }
                if (format == "int" || format == "int32") {
                    return "Int"
                }
                return "Double"
            case 'long':
            case 'int64':
                return 'Long'
            case 'bigdecimal':
            case 'double':
                return 'Double'
            case 'float':
                return 'Float'
            case 'string':
                return 'String'
            case 'boolean':
                return 'Boolean'
            case 'file':
                return 'Any'
            case 'array':
            case 'list':
                def refType = getType(property["items"])
                return "List<${refType}>"
            case 'object':
                return 'Any'
//                if (property["additionalProperties"]) return 'Any'
//                if (ref.$ref.includes('ReportUnit')) return 'Any'
//                def jsonOutput = new JsonOutput()
//                def result = jsonOutput.toJson(property)
//                throw new Exception("case 'object': 无法识别的属性类型  ${result}")
            default:
                if (type.contains(',')) {
                    def typeArr = type.split(',')
                    def defaultStr = ""
                    typeArr.each {
                        defaultStr += this.apiDocs["definitions"][it] ? this.getType(it, ref) : this.getType(["type": it])
                        defaultStr += ","
                    }
                    defaultStr = defaultStr.substring(0, defaultStr.length() - 1)
                    return defaultStr
                }
                def jsonOutput = new JsonOutput()
                def result1 = jsonOutput.toJson(property)
                def result2 = jsonOutput.toJson(ref)

                throw new Exception("case default 无法识别的属性类型 ${type} ${result1} ${result2}")
        }
    }

    private String getRefType(String refType, Object ref) {
        if (this.typeDefinitionMap.containsKey(refType)) {
            return this.typeDefinitionMap.get(refType).typeName
        }
        def generatorClass = ''
        def baseClass = ''

        if (refType.indexOf('«') > -1) {
            def gen = '<T>'
            if (refType.contains(',')) gen = '<T,T1>'
            if (gen == 'Map<T,T1>') return refType
            generatorClass = refType.substring(0, refType.indexOf('«')) + gen
            baseClass = refType.substring(refType.indexOf('«') + 1)
            baseClass = baseClass.substring(0, baseClass.lastIndexOf('»'))
            this.getRefType(baseClass, ref)
            if (this.typeDefinitionMap.containsKey(generatorClass)) return getGenerateName(refType)
        }

        def definition = this.apiDocs["definitions"][refType]
        if (!definition) {
            if (refType.indexOf('«') > -1) {
                println('invalidateTypes:' + refType)
                return refType
            }
            return this.getType(["type": refType], ref)
        }
        TsType typeDefinition = new TsType()
        typeDefinition.setDescription(definition["description"])
        typeDefinition.setTypeName(refType)
        def properties = new HashMap<String, TsTypeProperty>()
        typeDefinition.setProperties(properties)

        if (generatorClass) {
            typeDefinition.setTypeName(generatorClass)
            this.typeDefinitionMap.put(generatorClass, typeDefinition)
        } else {
            this.typeDefinitionMap.put(refType, typeDefinition)
        }

        if (definition["type"] != 'object') {
            throw new Exception("checkType 无法识别的类型${definition.type}")
        }
        definition["properties"].each {

            def propertyName = it.key
            def property = it.value
            try {
                def tsType = this.getType(property, ref)

                if (baseClass && (tsType == baseClass || tsType == "List<${baseClass}>")) {
                    tsType = tsType.replace(baseClass, 'T')
                }
                def name = getGenerateName(propertyName)
                def tsTypeProperty = new TsTypeProperty()
                tsTypeProperty.setName(name)
                tsTypeProperty.setType(getSimpleClass(tsType))
                tsTypeProperty.setFormat(property["format"])
                tsTypeProperty.setDescription(property["description"])
                typeDefinition.properties[name] = tsTypeProperty

            } catch (ex) {
                println(ex.message)

                def jsonOutput = new JsonOutput()
                def result = jsonOutput.toJson(property)
                throw new Exception("无法识别的属性类型 ${propertyName} ${result} ${refType} ")
            }
        }

        if (generatorClass) return getGenerateName(refType)

        return typeDefinition.typeName
    }

    private String getSimpleClass(String tsType) {
        return tsType?.replaceAll("<int", "<Int")
                .replaceAll("<integer", "<Int")
                .replaceAll("<number", "<Long")
                .replaceAll("<long", "<Long")
                .replaceAll("<string", "<String")
                .replaceAll("<boolean", "<Boolean")
                .replaceAll("int>", "Int>")
                .replaceAll("integer>", "Int>")
                .replaceAll("number>", "Long>")
                .replaceAll("long>", "Long>")
                .replaceAll("string>", "String>")
                .replaceAll("boolean>", "Boolean>")

                ?: tsType
    }

    private String getGenerateName(String className) {
        return className.replace("«", '<').replace("»", '>')
    }

    /**
     * 生成文件
     */
    private void generateFile() {
        this.generateEntityFile()
        this.generateApiFile()
        this.generateProviderFileFile()
    }
    /**
     * 生成类文件
     */
    private void generateEntityFile() {
        def parentPath = "./src/main/java/com/yryz/api/entity"
        def parentFile = new File(parentPath)
        if (!parentFile.exists()) {
            parentFile.mkdirs()
        }
        def file = new File(parentFile, "${serviceName}.kt")

        def tsContent = new StringBuilder()
        tsContent.append("package com.yryz.api.entity")
        tsContent.append("\n\n")
        tsContent.append("import java.io.Serializable")
        tsContent.append("\n\n")
        this.typeDefinitionMap.each {
            def typeInfoKey = it.key
            def typeInfo = it.value
            //排除Map定义

            if (typeInfo.typeName == 'Map<T>') return true
            if (typeInfo.typeName == 'Map<T,T1>') return true
            if (typeInfo.typeName == 'List<T>') return true

            if (classList.contains(typeInfo.typeName)) {
                return true
            }
            if (typeInfo.typeName == 'JsonNode') {
                classList.add("JsonNode")
                tsContent.append("class JsonNode(){}")
                tsContent.append("\n")
                return true
            }
            def properties = typeInfo.properties
            if (!properties || properties.isEmpty()) {
                classList.add(typeInfo.typeName)
                tsContent.append("class ${typeInfo.typeName}(){}")
                tsContent.append("\n")
                return true
            }

            classList.add(typeInfo.typeName)

            tsContent.append("data class ${typeInfo.typeName}(")
            tsContent.append("\n")

            def indexOf = 0
            properties.each {
                def propertyName = it.key
                def property = it.value
                if (property.description) {
                    tsContent.append("${spaces}/** ${property.description} */")
                    if (property.format != "" && property.format != null && property.format != "null") {
                        tsContent.append("\n")
                        tsContent.append("${spaces}/** 参数格式: ${property.format} */")
                    }
                    tsContent.append("\n")
                }
                tsContent.append("${spaces}var ${propertyName}: ${property.type}? = null")
                if (indexOf < properties.size() - 1) {
                    tsContent.append(",")
                }
                tsContent.append("\n")
                indexOf++
            }
            tsContent.append(')')

            if (configList.contains(typeInfo.typeName)) {
                tsContent.append(':Serializable')
            }
            tsContent.append("\n")

        }
        //生成类文件
        ResourceGroovyMethods.write(file, tsContent.toString(), "utf-8")
    }

    /**
     * 生成api文件
     */
    private void generateApiFile() {
        def parentPath = "./src/main/java/com/yryz/api/apiserver"
        def parentFile = new File(parentPath)
        if (!parentFile.exists()) {
            parentFile.mkdirs()
        }

        def fileName = transformCamelCase(serviceName)
        fileName = "${toUpperCaseOne(fileName)}ApiServer"
        def file = new File(parentFile, "${fileName}.kt")

        def tsContent = new StringBuilder()
        tsContent.append("package com.yryz.api.apiserver")
        tsContent.append("\n\n")
        tsContent.append("import com.yryz.network.http.model.BaseModel")
        tsContent.append("\n")
        tsContent.append("import io.reactivex.Observable")
        tsContent.append("\n")
        tsContent.append("import retrofit2.http.*")
        tsContent.append("\n")
        tsContent.append("import com.yryz.api.entity.*")

        tsContent.append("\n\n")
        tsContent.append("interface ${fileName} {")
        tsContent.append("\n\n")

        this.apiPaths.each {
            def className = it.key
            tsContent.append("${spacesInterface}interface ${toUpperCaseOne(className)}Server {")
            it.value.each {
                def methodName = it.key
                def apiInfo = it.value
                def url = apiInfo["url"]
                String method = apiInfo["method"]
                def parameters = apiInfo["parameters"]//[]
                def typeName = apiInfo["typeName"]

                def summary = apiInfo["summary"]
                //TODO parameters
                def paramsQuery = []
                def paramsPath = new HashMap<String, String>()
                String data = null

                parameters.each {
                    def p = it
                    def required = p["required"] ? '' : '?'
                    //def nameAndType = "${p["name"]}${required}: ${p["typeName"]}"
                    def nameAndType = "${p["name"]}: ${p["typeName"]}"
                    if (p["in"] == 'query') {
                        paramsQuery.add(nameAndType)
                    } else if (p["in"] == 'body') {
                        data = nameAndType
                    } else if (p["in"] == 'path') {
                        if (p["name"] != "version") {
                            paramsPath.put(p["name"], p["typeName"])
                        }
                    } else if (p["in"] == 'formData') {

                    }
                }
                def methodParams = ''

                if (summary && summary != methodName) {
                    tsContent.append("\n")
                    tsContent.append("${spacesInterfaceDouble}/**")
                    tsContent.append("\n")
                    tsContent.append("${spacesInterfaceDouble} * ${summary}")
                    tsContent.append("\n")
                    tsContent.append("${spacesInterfaceDouble} **/")
                    tsContent.append("\n")
                }

                if (parameters) {
                    tsContent.append("${spacesInterfaceDouble}/**")
                    tsContent.append("\n")
                    parameters.each {
                        def p = it
                        if (p["in"] == "header") {
                            return true
                        }
                        if (p["name"] == "version") {
                            return true
                        }
                        def required = p["required"] ? '必填' : '选填'
                        def nameAndType = "${p["in"]} ${p["name"]}:${p["typeName"]}${required})"
                        tsContent.append("${spacesInterfaceDouble}@${nameAndType}")
                        tsContent.append("\n")
                    }
                    tsContent.append("${spacesInterfaceDouble} **/")
                    tsContent.append("\n")
                }

                //   def appendUrl = "${this.serviceName}${url}/${d2}${p2}"
                //设置注解
                def methodComment = method.toUpperCase()
                if (method == "delete") {
                    methodComment = "HTTP"
                }
                def urlComment = "${this.serviceName}${url}"
                //设置请求
                def paramsComment = ""
                if (paramsPath) {
                    paramsPath.each {
                        def key = it.key
                        def value = it.value
                        if (!urlComment.contains("/{${key}}")) {
                            urlComment += "/{${key}}"
                        }
                        paramsComment += "@Path(\"${key}\") ${key}: String, "
                    }
                    paramsComment = paramsComment.substring(0, paramsComment.length() - ", ".length())
                }
                if (method == "delete") {
                    urlComment = "method = \"DELETE\", path = \"${urlComment}\", hasBody = true"
                } else {
                    urlComment = "\"${urlComment}\""
                }
                tsContent.append("${spacesInterfaceDouble}@${methodComment}(${urlComment})")
                tsContent.append("\n")

                if (method == "get") {
                    if (paramsQuery.size() > 0) {
                        paramsComment += paramsComment.length() > 0 ? ", " : ""
                        paramsComment += "@QueryMap params: MutableMap<String, Any>"
                    }
                } else if (method == "post"
                        || method == "delete"
                        || method == "put"
                ) {
                    if (data) {
                        paramsComment += paramsComment.length() > 0 ? ", " : ""
                        paramsComment += "@Body ${getSimpleClass(data)}"

                    }
                }
                tsContent.append("${spacesInterfaceDouble}fun ${methodName}(${paramsComment}): Observable<BaseModel<${getSimpleClass(getGenerateName(typeName))}>>")

                tsContent.append("\n")
            }
            tsContent.append("${spacesInterface}}")
            tsContent.append("\n\n")
        }
        tsContent.append("\n")
        tsContent.append("}")
        ResourceGroovyMethods.write(file, tsContent.toString(), "utf-8")

    }

    private void generateProviderFileFile() {
        def parentPath = "./src/main/java/com/yryz/api/provider"
        def parentFile = new File(parentPath)
        if (!parentFile.exists()) {
            parentFile.mkdirs()
        }
        def fileName = transformCamelCase(serviceName)
        fileName = "Provide${toUpperCaseOne(fileName)}ApiServer"
        def file = new File(parentFile, "${fileName}.kt")

        def tsContent = new StringBuilder()
        tsContent.append("package com.yryz.api.provider")
        tsContent.append("\n\n")
        tsContent.append("import com.yryz.network.http.retrofit.RetrofitManage")
        tsContent.append("\n")
        tsContent.append("import com.yryz.api.apiserver.*")
        tsContent.append("\n")

        tsContent.append("\n\n")
        tsContent.append("object ${fileName} {")
        tsContent.append("\n\n")

        def interfaceName = transformCamelCase(serviceName)
        interfaceName = "${toUpperCaseOne(interfaceName)}ApiServer"

        this.apiPaths.each {
            def className = it.key
            className = toUpperCaseOne(className)
            def functionName = "provide${className}Server"
            tsContent.append("${spacesInterface}fun ${functionName}(): ${interfaceName}.${className}Server =")
            tsContent.append("\n")
            tsContent.append("${spacesInterface}${spaces}RetrofitManage.instance.createService(${interfaceName}.${className}Server::class.java)")
            tsContent.append("\n\n")
        }
        tsContent.append("\n")

        tsContent.append("}")

        ResourceGroovyMethods.write(file, tsContent.toString(), "utf-8")

    }

    private String toUpperCaseOne(String string) {
        return "${string.substring(0, 1).toUpperCase()}${string.substring(1)}"
    }

}

对应的实体

package com.yryz.plugin

class TsTypeProperty {
    String name
    String type
    String description
    String format

}

package com.yryz.plugin
class TsType {
    String typeName
    String description
    Map<String, TsTypeProperty> properties
}

1.6 上传只本地mevan  ,点击 uploadArchives 命令,插件自动上传至本地meven

二 插件在工程中的应用

2.1 配置 projiect build.gradle,项目的build.gradle 需要配置本地meven 路径。

buildscript { 

    repositories {
        maven {
            url uri('./module_api_repository/') //配置本地meven
        }
        google()
        jcenter()
    }
    dependencies {

        classpath 'com.yryz.plugin:module-api-plugin:1.0.0'//配置插件
       }
}

2.2  插件在本地api module 中的使用,

2.2.1 module_api build.gradle 文件配置

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.yryz.plugin'//引入api 自动生成插件

2.2.2 apiConfig.json 配置文件,配置中的baseUrl+serviceName+version 为完整的获取swagger api 实体接口的url

{
  "serviceName": [
    "platform-behavior",//需要生成的微服务下的api
  ],
  "serializable": [
    "NewsInfoVO",//生成的实体需要序列化,继承serializable
  ],
  "custom": {
    "实例": {
      "vo": "返回实体",
      "params": "请求参数"
    }
  },
  "api": {
    "baseUrl": "swagger的base url https://xxx.xxx.xxx",
    "version": "服务对应的版本 v4/xx"
  }
}

2.2.3 api tak 的使用 执行 apiTask 命令,会生成对应的api 文件

2.2.4 生成的文件示例

//生成的api server 示例
interface PlatformBehaviorApiServer {

    interface CommentInfoServer {
        /**
         * 查询资源预览评论内容(首页)
         **/
        /**
        @query schemeType:String(选填)
        @query size:Int(选填)
        @query targetKid:List<String>(必填)
        @query targetType:String(必填)
         **/
        @GET("接口的url")
        fun searchPreview(@QueryMap params: MutableMap<String, Any>): Observable<BaseModel<Map<String,PageList<CommentContentDTO>>>>

        /**
         * 查询自己评论内容
         **/
        /**
        @body dto:CommentQueryDTO(必填)
         **/
        @POST("接口的url")
        fun searchUser(@Body dto: CommentQueryDTO): Observable<BaseModel<PageList<CommentContentDTO>>>

        /**
         * 删除评论(用户)
         **/
        /**
        @path commentKid:String(必填)
         **/
        @HTTP(method = "DELETE", path = "接口的url/{commentKid}", hasBody = true)
        fun delete(@Path("commentKid") commentKid: String): Observable<BaseModel<Long>>

    }
}

//生成的实体示例
data class CommentContentDTO(
        /** 父级用户对象 */
        var parent: CommentUserDTO? = null,
        /** 评论作者唯一标识 */
        var createUserId: String? = null,
        /** 子评论集合 */
        var subs: List<CommentContentDTO>? = null,
        /** 根级评论标识 */
        /** 参数格式: int64 */
        var rootKid: Long? = null,
        /** 评论唯一标识 */
        /** 参数格式: int64 */
        var kid: Long? = null,
        /** 删除标识 */
        /** 参数格式: int32 */
        var delFlag: Int? = null,
        /** 热度值 */
        /** 参数格式: int64 */
        var hotValue: Long? = null,
        /** 评论内容 */
        var content: String? = null,
        /** 审核标识(0无需审核/审核通过,1待审核,2审核拒绝) */
        /** 参数格式: int32 */
        var auditFlag: Int? = null,
        var statisticResult: StatisticResult? = null,
        /** 目标资源唯一标识 */
        var targetKid: String? = null,
        /** 评论类型(1 正常评论,2马甲评论,3灌水(机器人)评论 */
        var commentType: String? = null,
        /** 子评论总数 */
        /** 参数格式: int64 */
        var subTotalCount: Long? = null,
        /** 评论作者用户类型(1正常用户,2马甲用户,3机器人用户) */
        var createUserType: String? = null,
        /** 父级评论标识 */
        /** 参数格式: int64 */
        var parentKid: Long? = null,
        /** 创建时间 */
        /** 参数格式: date-time */
        var createDate: String? = null,
        /** 当前用户对象 */
        var creator: CommentUserDTO? = null,
        /** 评论作者用户类型(1正常用户,2马甲用户,3机器人用户) */
        var parentUserType: String? = null,
        /** 商户关联信息对象 */
        var relationalWithMerchant: CommentUserDTO? = null,
        /** 父级评论作者标识 */
        var parentUserId: String? = null,
        /** 目标资源类型 */
        var targetType: String? = null,
        /** 目标资源作者标识 */
        var targetUserId: String? = null,
        /** 租户唯一标识 */
        var tenantId: String? = null,
        /** 关联标示 */
        var relationKid: String? = null,
        var behaviorResult: UserBehaviorResult? = null
):Serializable

//生成的api api 方法示例
object ProvidePlatformBehaviorApiServer {

    fun provideCommentInfoServer(): PlatformBehaviorApiServer.CommentInfoServer =
            RetrofitManage.instance.createService(PlatformBehaviorApiServer.CommentInfoServer::class.java)
}

最后,就是在项目中愉快的使用了。

最后贴上 flutter api 生成的dart 版地址:juejin.cn/post/686485…