diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aaed3c..402a663 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ 4. 新增ApiDataBuilder中获取树形格式参数数据的接口#40。 5. 新增对Open Api 3.0的支持。 6. 修改字典表空时内部发生空指针的问题。 + 7. 优化curl用例,增加请求头。 #### 版本号:1.9.1 - 更新日期: 2020-08-02 - 更新内容: diff --git a/README.md b/README.md index 5bb597b..8acdfd9 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,9 @@ When you need to use smart-doc to generate more API document information, you ca "allInOneDocFileName":"index.html",//Customize the output document name "requestExample":"true",//Whether to display the request example in the document, the default value is true. "responseExample":"true",//Whether to display the response example in the document, the default is true. + "ignoreRequestParams":[ //The request parameter object will be discarded when generating the document.@since 1.9.2 + "org.springframework.ui.ModelMap" + ],   "dataDictionaries": [// Configure the data dictionary, no need to set     {       "title": "Order Status", // The name of the data dictionary diff --git a/README_CN.md b/README_CN.md index 8b0247c..1c35dca 100644 --- a/README_CN.md +++ b/README_CN.md @@ -4,7 +4,8 @@ smart-doc是一款同时支持JAVA RESTFUL API和Apache Dubbo RPC接口文档生成的工具,smart-doc在业内率先提出基于java泛型定义推导的理念, 完全基于接口源码来分析生成接口文档,不采用任何注解侵入到业务代码中。你只需要按照java-doc标准编写注释, smart-doc就能帮你生成一个简易明了的markdown、html5文档,甚至可以直接生成postman collection导入到postman做api接口调试。 -如果你已经厌倦了swagger等文档工具的无数注解和强侵入污染,那请拥抱smart-doc吧! + +$\color{red}{我因不将就而诞生,用了无数个日日夜夜来成长,无论现在还是将来也不会为了将就全世界!—smart-doc}$ ## Features - 零注解、零学习成本、只需要写标准java注释。 - 基于源代码接口定义自动推导,强大的返回结构推导。 @@ -95,6 +96,9 @@ smart-doc官方目前已经开发完成[maven插件](https://gitee.com/sunyurepo "allInOneDocFileName":"index.html",//自定义设置输出文档名称, @since 1.9.0 "requestExample":"true",//是否将请求示例展示在文档中,默认true,@since 1.9.0 "responseExample":"true",//是否将响应示例展示在文档中,默认为true,@since 1.9.0 + "ignoreRequestParams":[ //忽略请求参数对象,把不想生成文档的参数对象屏蔽掉,@since 1.9.2 + "org.springframework.ui.ModelMap" + ], "dataDictionaries": [ //配置数据字典,没有需求可以不设置 { "title": "http状态码字典", //数据字典的名称 @@ -103,14 +107,12 @@ smart-doc官方目前已经开发完成[maven插件](https://gitee.com/sunyurepo "descField": "message"//数据字典对象的描述信息字典 } ], - "errorCodeDictionaries": [{ //错误码列表,没有需求可以不设置 "title": "title", "enumClassName": "com.power.common.enums.HttpCodeEnum", //错误码枚举类 "codeField": "code",//错误码的code码字段名称 "descField": "message"//错误码的描述信息对应的字段名 }], - "revisionLogs": [ //设置文档变更记录,没有需求可以不设置 { "version": "1.0", //文档版本号 @@ -181,7 +183,7 @@ mvn -Dfile.encoding = UTF-8 smart-doc:rpc-adoc ``` **注意:** 尤其在window系统下,如果实际使用maven命令行执行文档生成,可能会出现乱码,因此需要在执行时指定`-Dfile.encoding=UTF-8`。 #### Use Idea -![idea中smart-doc-maven插件使用](https://images.gitee.com/uploads/images/2020/0602/213139_739a4d41_144669.png "maven_plugin_tasks.png") +![idea中smart-doc-maven插件使用](https://gitee.com/sunyurepository/smart-doc-maven-plugin/raw/master/images/idea.png "maven_plugin_tasks.png") ### Use gradle plugin 如果你使用gradle来构建项目,你可以参考gradle插件的使用文档来集成, diff --git a/pom.xml b/pom.xml index 8df9ea2..3a5078a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,174 +1,174 @@ - - - com.github.shalousun - 4.0.0 - smart-doc - jar - 1.9.1 - - smart-doc - https://github.com/shalousun/smart-doc.git - Smart-doc is a tool that supports both JAVA RESTFUL API and Apache Dubbo RPC interface document generation. - - - - The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - https://github.com/shalousun/smart-doc.git - scm:https://github.com/shalousun/smart-doc.git - scm:https://github.com/shalousun/smart-doc.git - - - - shalousun - 836575280@qq.com - https://github.com/shalousun - - - - UTF-8 - 0.62.2 - - - - junit - junit - 4.13 - test - - - com.ibeetl - beetl - 3.1.8.RELEASE - - - com.thoughtworks.qdox - qdox - 2.0.0 - - - com.github.javafaker - javafaker - 1.0.2 - - - commons-lang3 - org.apache.commons - - - - - com.github.shalousun - common-util - 1.9.6 - - - - com.vladsch.flexmark - flexmark - ${flexmark.version} - - - com.vladsch.flexmark - flexmark-util - ${flexmark.version} - - - com.vladsch.flexmark - flexmark-ext-tables - ${flexmark.version} - - - com.vladsch.flexmark - flexmark-ext-gfm-strikethrough - ${flexmark.version} - - - com.google.code.gson - gson - 2.8.6 - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.1 - - 1.8 - 1.8 - UTF-8 - - - - - org.apache.maven.plugins - maven-source-plugin - 3.2.1 - - - package - - jar-no-fork - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 3.2.0 - - - package - - jar - - - - - - smart-doc - - - - release - - - - org.apache.maven.plugins - maven-gpg-plugin - 1.6 - - - sign-artifacts - verify - - sign - - - - - - - - - oss - https://oss.sonatype.org/content/repositories/snapshots/ - - - oss - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - - + + + com.github.shalousun + 4.0.0 + smart-doc + jar + 1.9.2.1 + + smart-doc + https://github.com/shalousun/smart-doc.git + Smart-doc is a tool that supports both JAVA RESTFUL API and Apache Dubbo RPC interface document generation. + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + https://github.com/shalousun/smart-doc.git + scm:https://github.com/shalousun/smart-doc.git + scm:https://github.com/shalousun/smart-doc.git + + + + shalousun + 836575280@qq.com + https://github.com/shalousun + + + + UTF-8 + 0.62.2 + + + + junit + junit + 4.13 + test + + + com.ibeetl + beetl + 3.1.8.RELEASE + + + com.thoughtworks.qdox + qdox + 2.0.0 + + + com.github.javafaker + javafaker + 1.0.2 + + + commons-lang3 + org.apache.commons + + + + + com.github.shalousun + common-util + 1.9.7 + + + + com.vladsch.flexmark + flexmark + ${flexmark.version} + + + com.vladsch.flexmark + flexmark-util + ${flexmark.version} + + + com.vladsch.flexmark + flexmark-ext-tables + ${flexmark.version} + + + com.vladsch.flexmark + flexmark-ext-gfm-strikethrough + ${flexmark.version} + + + com.google.code.gson + gson + 2.8.6 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + + + + + org.apache.maven.plugins + maven-source-plugin + 3.2.1 + + + package + + jar-no-fork + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.2.0 + + + package + + jar + + + + + + smart-doc + + + + release + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + + + oss + https://oss.sonatype.org/content/repositories/snapshots/ + + + oss + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + diff --git a/src/main/java/com/power/doc/builder/AdocDocBuilder.java b/src/main/java/com/power/doc/builder/AdocDocBuilder.java index 8208b7c..2799f53 100644 --- a/src/main/java/com/power/doc/builder/AdocDocBuilder.java +++ b/src/main/java/com/power/doc/builder/AdocDocBuilder.java @@ -48,7 +48,7 @@ public class AdocDocBuilder { * * @param config ApiConfig */ - public static void builderApiDoc(ApiConfig config) { + public static void buildApiDoc(ApiConfig config) { JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder(); buildApiDoc(config, javaProjectBuilder); } diff --git a/src/main/java/com/power/doc/builder/DocBuilderTemplate.java b/src/main/java/com/power/doc/builder/DocBuilderTemplate.java index ffa9e7a..3bfcceb 100644 --- a/src/main/java/com/power/doc/builder/DocBuilderTemplate.java +++ b/src/main/java/com/power/doc/builder/DocBuilderTemplate.java @@ -80,6 +80,8 @@ public class DocBuilderTemplate extends BaseDocBuilderTemplate { mapper.binding(TemplateVariable.DESC.getVariable(), doc.getDesc()); mapper.binding(TemplateVariable.NAME.getVariable(), doc.getName()); mapper.binding(TemplateVariable.LIST.getVariable(), doc.getList()); + mapper.binding(TemplateVariable.REQUEST_EXAMPLE.getVariable(), config.isRequestExample()); + mapper.binding(TemplateVariable.RESPONSE_EXAMPLE.getVariable(), config.isResponseExample()); FileUtil.nioWriteFile(mapper.render(), config.getOutPath() + FILE_SEPARATOR + doc.getName() + fileExtension); } } diff --git a/src/main/java/com/power/doc/builder/HtmlApiDocBuilder.java b/src/main/java/com/power/doc/builder/HtmlApiDocBuilder.java index 55d5862..7d3ee5f 100644 --- a/src/main/java/com/power/doc/builder/HtmlApiDocBuilder.java +++ b/src/main/java/com/power/doc/builder/HtmlApiDocBuilder.java @@ -93,7 +93,7 @@ public class HtmlApiDocBuilder { List apiDocDictList = builderTemplate.buildDictionary(config, javaProjectBuilder); buildIndex(apiDocList, config); copyCss(config.getOutPath()); - buildDoc(apiDocList, config.getOutPath()); + buildDoc(apiDocList, config); buildErrorCodeDoc(config.getErrorCodes(), config.getOutPath()); buildDictionary(apiDocDictList, config.getOutPath()); } @@ -149,20 +149,22 @@ public class HtmlApiDocBuilder { * build ever controller api * * @param apiDocList list of api doc - * @param outPath output path + * @param config ApiConfig */ - private static void buildDoc(List apiDocList, String outPath) { - FileUtil.mkdirs(outPath); + private static void buildDoc(List apiDocList, ApiConfig config) { + FileUtil.mkdirs(config.getOutPath()); Template htmlApiDoc; for (ApiDoc doc : apiDocList) { Template apiTemplate = BeetlTemplateUtil.getByName(API_DOC_MD_TPL); + apiTemplate.binding(TemplateVariable.REQUEST_EXAMPLE.getVariable(), config.isRequestExample()); + apiTemplate.binding(TemplateVariable.RESPONSE_EXAMPLE.getVariable(), config.isResponseExample()); apiTemplate.binding(TemplateVariable.DESC.getVariable(), doc.getDesc()); apiTemplate.binding(TemplateVariable.NAME.getVariable(), doc.getName()); apiTemplate.binding(TemplateVariable.LIST.getVariable(), doc.getList());//类名 Map templateVariables = new HashMap<>(); templateVariables.put(TemplateVariable.TITLE.getVariable(), doc.getDesc()); htmlApiDoc = initTemplate(apiTemplate, HTML_API_DOC_TPL, templateVariables); - FileUtil.nioWriteFile(htmlApiDoc.render(), outPath + FILE_SEPARATOR + doc.getAlias() + ".html"); + FileUtil.nioWriteFile(htmlApiDoc.render(), config.getOutPath() + FILE_SEPARATOR + doc.getAlias() + ".html"); } } diff --git a/src/main/java/com/power/doc/builder/YapiJsonBuilder.java b/src/main/java/com/power/doc/builder/YapiJsonBuilder.java new file mode 100644 index 0000000..671ef3a --- /dev/null +++ b/src/main/java/com/power/doc/builder/YapiJsonBuilder.java @@ -0,0 +1,251 @@ +/* + * smart-doc https://github.com/shalousun/smart-doc + * + * Copyright (C) 2019-2020 smart-doc + * + * 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 com.power.doc.builder; + + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.power.common.util.FileUtil; +import com.power.common.util.StringUtil; +import com.power.doc.constants.DocGlobalConstants; +import com.power.doc.constants.TemplateVariable; +import com.power.doc.model.ApiConfig; +import com.power.doc.model.ApiDoc; +import com.power.doc.model.ApiParam; +import com.power.doc.template.IDocBuildTemplate; +import com.power.doc.template.SpringBootDocBuildTemplate; +import com.power.doc.utils.BeetlTemplateUtil; +import com.power.doc.utils.Iterables; +import com.thoughtworks.qdox.JavaProjectBuilder; +import org.beetl.core.Template; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.power.doc.constants.DocGlobalConstants.YAPI_RESULT_TPL; + + +/** + * generate yapi's yapi json + * + * @author dai19470 2020/08/20. + */ +public class YapiJsonBuilder { + + + /** + * 构建yapi json + * + * @param config 配置文件 + */ + public static void buildYapiCollection(ApiConfig config) { + DocBuilderTemplate builderTemplate = new DocBuilderTemplate(); + builderTemplate.checkAndInit(config); + JavaProjectBuilder javaProjectBuilder = new JavaProjectBuilder(); + ProjectDocConfigBuilder configBuilder = new ProjectDocConfigBuilder(config, javaProjectBuilder); + yapiJsonCreate(config, configBuilder); + } + + + private static Set getUrl(String url, String patter) { + Pattern pattern = Pattern.compile(patter); + Matcher matcher = pattern.matcher(url); + Set result = new HashSet<>(); + while (matcher.find()) { + result.add(matcher.group()); + } + return result; + } + + private static void yapiJsonCreate(ApiConfig config, ProjectDocConfigBuilder configBuilder) { + config.setParamsDataToTree(true); + IDocBuildTemplate docBuildTemplate = new SpringBootDocBuildTemplate(); + List apiDocList = docBuildTemplate.getApiData(configBuilder); + List> requestItem = new ArrayList<>(); + + Iterables.forEach(apiDocList, (index, apiDoc) -> { + Map module = new HashMap<>(); + module.put("index", index); + module.put("name", apiDoc.getDesc()); + module.put("parent_id", -1); + module.put("desc", apiDoc.getDesc()); + module.put("add_time", System.currentTimeMillis() / 1000); + module.put("up_time", System.currentTimeMillis() / 1000); + + List> methods = new ArrayList(); + + Iterables.forEach(apiDoc.getList(), (idx, apiMethodDoc) -> { + Map method = new HashMap<>(); + Map map = new HashMap<>(); + map.put("path", apiMethodDoc.getPath()); + map.put("params", new Object[]{}); + method.put("query_path", map); + // method.put("owners",new String[]{apiMethodDoc.getAuthor()}); + method.put("owners", new String[]{}); + method.put("edit_uid", 0); + method.put("status", "done"); + method.put("type", "static"); + method.put("req_body_is_json_schema", true); + method.put("res_body_is_json_schema", true); + method.put("api_opened", false); + method.put("index", idx); + method.put("tag", new Object[]{}); + method.put("method", apiMethodDoc.getType()); + method.put("title", apiMethodDoc.getDesc()); + method.put("desc", apiMethodDoc.getDetail()); + method.put("name", apiMethodDoc.getName()); + method.put("path", apiMethodDoc.getPath().replace("//", "/")); + method.put("req_body_form", Arrays.asList()); + + + List> req_params = new ArrayList(); + Set req_param = getUrl(apiMethodDoc.getPath(), "(?<=\\{)(.+?)(?=\\})"); + Iterables.forEach(req_param, (j, param) -> { + ApiParam temp = apiMethodDoc.getRequestParams().stream().filter(apiParam -> apiParam.getField().equals(param)).findFirst().orElse(null); + if (temp != null) { + Map h = new HashMap<>(); + h.put("example", ""); + h.put("name", temp.getField()); + h.put("type", temp.getType()); + h.put("desc", temp.getDesc()); + req_params.add(j, h); + } + }); + method.put("req_params", req_params); + + method.put("res_body_type", "json"); + List> querys = new ArrayList(); + Iterables.forEach(apiMethodDoc.getRequestParams(), (j, res) -> { + Map h = new HashMap<>(); + h.put("required", res.isRequired() ? "1" : "0"); + h.put("desc", res.getDesc()); + h.put("name", res.getField()); + h.put("example", ""); + h.put("type", res.getType()); + querys.add(j, h); + }); + method.put("req_query", querys); + + List> headers = new ArrayList(); + Iterables.forEach(apiMethodDoc.getRequestHeaders(), (j, res) -> { + Map h = new HashMap<>(); + h.put("required", res.isRequired() ? "1" : "0"); + h.put("value", res.getValue()); + h.put("name", res.getName()); + h.put("desc", res.getDesc()); + headers.add(j, h); + }); + + method.put("req_headers", headers); + + Template apiTemplate = BeetlTemplateUtil.getByName(YAPI_RESULT_TPL); + + apiTemplate.binding(TemplateVariable.RESPONSELIST.getVariable(), generateJson(apiMethodDoc.getResponseParams())); + String json = apiTemplate.render(); + method.put("res_body", json); + + if (StringUtil.isNotEmpty(apiMethodDoc.getResponseUsage())) { + method.put("desc", "
\n" + apiMethodDoc.getResponseUsage() + "\n
\n"); + } + + methods.add(idx, method); + }); + module.put("list", methods); + + requestItem.add(module); + }); + + String filePath = config.getOutPath(); + filePath = filePath + DocGlobalConstants.YAPI_JSON; + Gson gson = new GsonBuilder().setPrettyPrinting().create(); + String data = gson.toJson(requestItem); + FileUtil.nioWriteFile(data, filePath); + } + + private static String generateJson(List responseParams) { + StringBuffer re = new StringBuffer("\"type\":\"object\",\n\"properties\":{\n"); + HashSet required = new HashSet<>(); + responseParams.stream().forEach(apiParam -> { + re.append(getTypeAndPropertiesJson(apiParam)); + if (apiParam.isRequired()) { + required.add(apiParam.getField()); + } + }); + Gson gs = new Gson(); + re.append("\"required\":\"" + gs.toJson(required.toArray()) + "\""); + re.append("\t}"); + return re.toString(); + } + + /** + * 将字段类型转换为yapi的字段类型 + * + * @param type java type + * @return String + */ + public static String changeType(String type) { + switch (type) { + case "boolean": + return "boolean"; + case "int32": + return "integer"; + case "int64": + return "number"; + default: + return type; + } + } + + /** + * 单个参数拼接字符串 + * + * @param param ApiParam + * @return String + */ + public static String getTypeAndPropertiesJson(ApiParam param) { + StringBuffer resultJson = new StringBuffer(); + + resultJson.append("\"" + param.getField() + "\":{"); + resultJson.append("\"type\":\"" + changeType(param.getType()) + "\", "); + + if (param.getChildren() != null && param.getChildren().size() > 0) { + if (param.getType().equals("object")) { + resultJson.append(" \"properties\":{"); + param.getChildren().forEach(child -> { + resultJson.append(getTypeAndPropertiesJson(child)); + }); + } else if (param.getType().equals("array")) { + resultJson.append(" \"items\":{"); + resultJson.append("\"type\":\"object\",\n\"properties\":{\n"); + param.getChildren().forEach(child -> { + resultJson.append(getTypeAndPropertiesJson(child)); + }); + resultJson.append("\t},"); + } + resultJson.append("},"); + } + resultJson.append("},"); + return resultJson.toString(); + } +} diff --git a/src/main/java/com/power/doc/constants/DocGlobalConstants.java b/src/main/java/com/power/doc/constants/DocGlobalConstants.java index c2202cc..fddda89 100644 --- a/src/main/java/com/power/doc/constants/DocGlobalConstants.java +++ b/src/main/java/com/power/doc/constants/DocGlobalConstants.java @@ -1,149 +1,151 @@ -package com.power.doc.constants; - -/** - * @author yu 2018/12/15. - */ -public interface DocGlobalConstants { - - String FILE_SEPARATOR = System.getProperty("file.separator"); - - String HTML_DOC_OUT_PATH = "src/main/resources/static/doc"; - - String ADOC_OUT_PATH = "src/docs/asciidoc"; - - String PROJECT_CODE_PATH = "src" + FILE_SEPARATOR + "main" + FILE_SEPARATOR + "java"; - - String ABSOLUTE_CODE_PATH = System.getProperty("user.dir") + FILE_SEPARATOR + PROJECT_CODE_PATH; - - String DOC_LANGUAGE = "smart-doc_language"; - - String API_DOC_MD_TPL = "ApiDoc.btl"; - - String API_DOC_ADOC_TPL = "ApiDoc.adoc"; - - String ALL_IN_ONE_MD_TPL = "AllInOne.btl"; - - String ALL_IN_ONE_ADOC_TPL = "AllInOne.adoc"; - - String ALL_IN_ONE_HTML_TPL = "AllInOne.html"; - - String HTML_API_DOC_TPL = "HtmlApiDoc.btl"; - - String ERROR_CODE_LIST_MD_TPL = "ErrorCodeList.btl"; - - String ERROR_CODE_LIST_ADOC_TPL = "ErrorCodeList.adoc"; - - String ERROR_CODE_LIST_MD = "ErrorCodeList.md"; - - String ERROR_CODE_LIST_ADOC = "ErrorCodeList.adoc"; - - String DICT_LIST_MD = "Dictionary.md"; - - String DICT_LIST_MD_TPL = "Dictionary.btl"; - - String DICT_LIST_ADOC = "Dictionary.adoc"; - - String DICT_LIST_ADOC_TPL = "Dictionary.btl"; - - String INDEX_TPL = "Index.btl"; - - String INDEX_CSS_TPL = "index.css"; - - String MARKDOWN_CSS_TPL = "markdown.css"; - - String ALL_IN_ONE_CSS = "AllInOne.css"; - - String RPC_API_DOC_ADOC_TPL = "dubbo/Dubbo.adoc"; - - String RPC_ALL_IN_ONE_ADOC_TPL = "dubbo/DubboAllInOne.adoc"; - - String RPC_ALL_IN_ONE_HTML_TPL = "dubbo/DubboAllInOne.html"; - - String RPC_DEPENDENCY_MD_TPL = "dubbo/DubboApiDependency.md"; - - String RPC_API_DOC_MD_TPL = "dubbo/Dubbo.md"; - - String RPC_ALL_IN_ONE_MD_TPL = "dubbo/DubboAllInOne.md"; - - String RPC_INDEX_TPL = "dubbo/DubboIndex.btl"; - - String POSTMAN_JSON = "/postman.json"; - - String OPEN_API_JSON = "/openApi3.0.json"; - - String CONTROLLER_FULLY = "org.springframework.stereotype.Controller"; - - String REST_CONTROLLER_FULLY = "org.springframework.web.bind.annotation.RestController"; - - String GET_MAPPING_FULLY = "org.springframework.web.bind.annotation.GetMapping"; - - String POST_MAPPING_FULLY = "org.springframework.web.bind.annotation.PostMapping"; - - String PUT_MAPPING_FULLY = "org.springframework.web.bind.annotation.PutMapping"; - - String PATCH_MAPPING_FULLY = "org.springframework.web.bind.annotation.PatchMapping"; - - String DELETE_MAPPING_FULLY = "org.springframework.web.bind.annotation.DeleteMapping"; - - String REQUEST_MAPPING_FULLY = "org.springframework.web.bind.annotation.RequestMapping"; - - String REQUEST_BODY_FULLY = "org.springframework.web.bind.annotation.RequestBody"; - - String MODE_AND_VIEW_FULLY = "org.springframework.web.servlet.ModelAndView"; - - String MULTIPART_FILE_FULLY = "org.springframework.web.multipart.MultipartFile"; - - String JAVA_OBJECT_FULLY = "java.lang.Object"; - - String JAVA_STRING_FULLY = "java.lang.String"; - - String JAVA_MAP_FULLY = "java.util.Map"; - - String JAVA_LIST_FULLY = "java.util.List"; - - String DEFAULT_VERSION = "-"; - - String ERROR_CODE_LIST_CN_TITLE = "错误码列表"; - - String ERROR_CODE_LIST_EN_TITLE = "Error Code List"; - - String DICT_CN_TITLE = "数据字典"; - - String DICT_EN_TITLE = "Data Dictionaries"; - - String FIELD_SPACE = "     "; - - String ANY_OBJECT_MSG = "any object."; - - String NO_COMMENTS_FOUND = "No comments found."; - - String SPRING_WEB_ANNOTATION_PACKAGE = "org.springframework.web.bind.annotation"; - - String FILE_CONTENT_TYPE = "multipart/form-data"; - - String MULTIPART_TYPE = "multipart/form-data"; - - String APPLICATION_JSON = "application/json"; - - String JSON_CONTENT_TYPE = "application/json; charset=utf-8"; - - String POSTMAN_MODE_FORMDATA = "formdata"; - - String POSTMAN_MODE_RAW = "raw"; - - String SHORT_MULTIPART_FILE_FULLY = "MultipartFile"; - - String DEFAULT_SERVER_URL = "http://{server}"; - - String SHORT_REQUEST_BODY = "RequestBody"; - - String CURL_REQUEST_TYPE = "curl -X %s -i %s"; - - String CURL_REQUEST_TYPE_DATA = "curl -X %s -i %s --data '%s'"; - - String CURL_POST_PUT_JSON = "curl -X %s -H 'Content-Type: application/json; charset=utf-8' -i %s --data '%s'"; - - String EMPTY = ""; - - String ENUM = "enum"; -} +package com.power.doc.constants; + +/** + * @author yu 2018/12/15. + */ +public interface DocGlobalConstants { + + String FILE_SEPARATOR = System.getProperty("file.separator"); + + String HTML_DOC_OUT_PATH = "src/main/resources/static/doc"; + + String ADOC_OUT_PATH = "src/docs/asciidoc"; + + String PROJECT_CODE_PATH = "src" + FILE_SEPARATOR + "main" + FILE_SEPARATOR + "java"; + + String ABSOLUTE_CODE_PATH = System.getProperty("user.dir") + FILE_SEPARATOR + PROJECT_CODE_PATH; + + String DOC_LANGUAGE = "smart-doc_language"; + + String API_DOC_MD_TPL = "ApiDoc.btl"; + + String API_DOC_ADOC_TPL = "ApiDoc.adoc"; + + String ALL_IN_ONE_MD_TPL = "AllInOne.btl"; + + String ALL_IN_ONE_ADOC_TPL = "AllInOne.adoc"; + + String ALL_IN_ONE_HTML_TPL = "AllInOne.html"; + + String HTML_API_DOC_TPL = "HtmlApiDoc.btl"; + + String ERROR_CODE_LIST_MD_TPL = "ErrorCodeList.btl"; + + String ERROR_CODE_LIST_ADOC_TPL = "ErrorCodeList.adoc"; + + String ERROR_CODE_LIST_MD = "ErrorCodeList.md"; + + String ERROR_CODE_LIST_ADOC = "ErrorCodeList.adoc"; + + String DICT_LIST_MD = "Dictionary.md"; + + String DICT_LIST_MD_TPL = "Dictionary.btl"; + + String DICT_LIST_ADOC = "Dictionary.adoc"; + + String DICT_LIST_ADOC_TPL = "Dictionary.btl"; + + String INDEX_TPL = "Index.btl"; + + String INDEX_CSS_TPL = "index.css"; + + String MARKDOWN_CSS_TPL = "markdown.css"; + + String ALL_IN_ONE_CSS = "AllInOne.css"; + + String RPC_API_DOC_ADOC_TPL = "dubbo/Dubbo.adoc"; + + String RPC_ALL_IN_ONE_ADOC_TPL = "dubbo/DubboAllInOne.adoc"; + + String RPC_ALL_IN_ONE_HTML_TPL = "dubbo/DubboAllInOne.html"; + + String RPC_DEPENDENCY_MD_TPL = "dubbo/DubboApiDependency.md"; + + String RPC_API_DOC_MD_TPL = "dubbo/Dubbo.md"; + + String RPC_ALL_IN_ONE_MD_TPL = "dubbo/DubboAllInOne.md"; + + String RPC_INDEX_TPL = "dubbo/DubboIndex.btl"; + + String POSTMAN_JSON = "/postman.json"; + + String OPEN_API_JSON = "/openApi3.0.json"; + + String CONTROLLER_FULLY = "org.springframework.stereotype.Controller"; + + String REST_CONTROLLER_FULLY = "org.springframework.web.bind.annotation.RestController"; + + String GET_MAPPING_FULLY = "org.springframework.web.bind.annotation.GetMapping"; + + String POST_MAPPING_FULLY = "org.springframework.web.bind.annotation.PostMapping"; + + String PUT_MAPPING_FULLY = "org.springframework.web.bind.annotation.PutMapping"; + + String PATCH_MAPPING_FULLY = "org.springframework.web.bind.annotation.PatchMapping"; + + String DELETE_MAPPING_FULLY = "org.springframework.web.bind.annotation.DeleteMapping"; + + String REQUEST_MAPPING_FULLY = "org.springframework.web.bind.annotation.RequestMapping"; + + String REQUEST_BODY_FULLY = "org.springframework.web.bind.annotation.RequestBody"; + + String MODE_AND_VIEW_FULLY = "org.springframework.web.servlet.ModelAndView"; + + String MULTIPART_FILE_FULLY = "org.springframework.web.multipart.MultipartFile"; + + String JAVA_OBJECT_FULLY = "java.lang.Object"; + + String JAVA_STRING_FULLY = "java.lang.String"; + + String JAVA_MAP_FULLY = "java.util.Map"; + + String JAVA_LIST_FULLY = "java.util.List"; + + String DEFAULT_VERSION = "-"; + + String ERROR_CODE_LIST_CN_TITLE = "错误码列表"; + + String ERROR_CODE_LIST_EN_TITLE = "Error Code List"; + + String DICT_CN_TITLE = "数据字典"; + + String DICT_EN_TITLE = "Data Dictionaries"; + + String FIELD_SPACE = "     "; + + String ANY_OBJECT_MSG = "any object."; + + String NO_COMMENTS_FOUND = "No comments found."; + + String SPRING_WEB_ANNOTATION_PACKAGE = "org.springframework.web.bind.annotation"; + + String FILE_CONTENT_TYPE = "multipart/form-data"; + + String MULTIPART_TYPE = "multipart/form-data"; + + String APPLICATION_JSON = "application/json"; + + String JSON_CONTENT_TYPE = "application/json; charset=utf-8"; + + String POSTMAN_MODE_FORMDATA = "formdata"; + + String POSTMAN_MODE_RAW = "raw"; + + String SHORT_MULTIPART_FILE_FULLY = "MultipartFile"; + + String DEFAULT_SERVER_URL = "http://{server}"; + + String SHORT_REQUEST_BODY = "RequestBody"; + + String CURL_REQUEST_TYPE = "curl -X %s %s -i %s"; + + String CURL_REQUEST_TYPE_DATA = "curl -X %s %s -i %s --data '%s'"; + + String CURL_POST_PUT_JSON = "curl -X %s -H 'Content-Type: application/json; charset=utf-8' %s -i %s --data '%s'"; + + String EMPTY = ""; + + String ENUM = "enum"; + String YAPI_RESULT_TPL = "yapiJson.btl"; + String YAPI_JSON="/yapi.json"; +} diff --git a/src/main/java/com/power/doc/constants/TemplateVariable.java b/src/main/java/com/power/doc/constants/TemplateVariable.java index 8f60654..0065989 100644 --- a/src/main/java/com/power/doc/constants/TemplateVariable.java +++ b/src/main/java/com/power/doc/constants/TemplateVariable.java @@ -48,7 +48,8 @@ public enum TemplateVariable { URI("uri"), RPC_CONSUMER_CONFIG("consumerConfigExample"), REQUEST_EXAMPLE("isRequestExample"), - RESPONSE_EXAMPLE("isResponseExample"); + RESPONSE_EXAMPLE("isResponseExample"), + RESPONSELIST("respList"); private String variable; diff --git a/src/main/java/com/power/doc/helper/ParamsBuildHelper.java b/src/main/java/com/power/doc/helper/ParamsBuildHelper.java index 279b9e7..a56df99 100644 --- a/src/main/java/com/power/doc/helper/ParamsBuildHelper.java +++ b/src/main/java/com/power/doc/helper/ParamsBuildHelper.java @@ -1,429 +1,429 @@ -/* - * smart-doc https://github.com/shalousun/smart-doc - * - * Copyright (C) 2018-2020 smart-doc - * - * 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 com.power.doc.helper; - -import com.power.common.model.EnumDictionary; -import com.power.common.util.CollectionUtil; -import com.power.common.util.StringUtil; -import com.power.doc.builder.ProjectDocConfigBuilder; -import com.power.doc.constants.DocAnnotationConstants; -import com.power.doc.constants.DocGlobalConstants; -import com.power.doc.constants.DocTags; -import com.power.doc.constants.ValidatorAnnotations; -import com.power.doc.model.*; -import com.power.doc.utils.*; -import com.thoughtworks.qdox.model.*; - -import java.util.*; -import java.util.stream.Collectors; - -import static com.power.doc.constants.DocGlobalConstants.NO_COMMENTS_FOUND; - -/** - * @author yu 2019/12/21. - */ -public class ParamsBuildHelper { - - public static List buildParams(String className, String pre, int level, String isRequired, - Map responseFieldMap, boolean isResp, - Map registryClasses, ProjectDocConfigBuilder projectBuilder, - List groupClasses, int pid) { - //存储泛型所对应的实体类 - Map genericMap = new HashMap<>(10); - - if (StringUtil.isEmpty(className)) { - throw new RuntimeException("Class name can't be null or empty."); - } - ApiConfig apiConfig = projectBuilder.getApiConfig(); - int nextLevel = level + 1; - // Check circular reference - List paramList = new ArrayList<>(); - if (level > apiConfig.getRecursionLimit()) { - return paramList; - } - if (registryClasses.containsKey(className) && level > registryClasses.size()) { - return paramList; - } - boolean skipTransientField = apiConfig.isSkipTransientField(); - boolean isShowJavaType = projectBuilder.getApiConfig().getShowJavaType(); - boolean requestFieldToUnderline = projectBuilder.getApiConfig().isRequestFieldToUnderline(); - boolean responseFieldToUnderline = projectBuilder.getApiConfig().isResponseFieldToUnderline(); - // Registry class - registryClasses.put(className, className); - String simpleName = DocClassUtil.getSimpleName(className); - String[] globGicName = DocClassUtil.getSimpleGicName(className); - JavaClass cls = projectBuilder.getClassByName(simpleName); - //如果存在泛型 则将泛型与类名的对应关系存起来 - if (cls != null && null != cls.getTypeParameters()) { - List> variables = cls.getTypeParameters(); - for (int i = 0; i < cls.getTypeParameters().size() && i fields = JavaClassUtil.getFields(cls, 0, new HashSet<>()); - if (JavaClassValidateUtil.isPrimitive(simpleName)) { - String processedType = isShowJavaType ? simpleName : DocClassUtil.processTypeNameForParams(simpleName.toLowerCase()); - paramList.addAll(primitiveReturnRespComment(processedType)); - } else if (JavaClassValidateUtil.isCollection(simpleName) || JavaClassValidateUtil.isArray(simpleName)) { - if (!JavaClassValidateUtil.isCollection(globGicName[0])) { - String gicName = globGicName[0]; - if (JavaClassValidateUtil.isArray(gicName)) { - gicName = gicName.substring(0, gicName.indexOf("[")); - } - paramList.addAll(buildParams(gicName, pre, nextLevel, isRequired, responseFieldMap, isResp, - registryClasses, projectBuilder, groupClasses, pid)); - } - } else if (JavaClassValidateUtil.isMap(simpleName)) { - if (globGicName.length == 2) { - paramList.addAll(buildParams(globGicName[1], pre, nextLevel, isRequired, responseFieldMap, isResp, - registryClasses, projectBuilder, groupClasses, pid)); - } - } else if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(className)) { - ApiParam param = ApiParam.of().setField(pre + "any object").setType("object").setPid(pid); - if (StringUtil.isEmpty(isRequired)) { - param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION); - } else { - param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setRequired(false).setVersion(DocGlobalConstants.DEFAULT_VERSION); - } - paramList.add(param); - } -// if (className.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) { -// ApiParam param = ApiParam.of().setField("").setType("file") -// .setPid(pid) -// .setDesc("comment").setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION); -// paramList.add(param); -// } - else { - boolean isGenerics = JavaFieldUtil.checkGenerics(fields); - out: - for (DocJavaField docField : fields) { - JavaField field = docField.getJavaField(); - String fieldName = field.getName(); - String subTypeName = field.getType().getFullyQualifiedName(); - if (field.isStatic() || "this$0".equals(fieldName) || - JavaClassValidateUtil.isIgnoreFieldTypes(subTypeName)) { - continue; - } - if (field.isTransient() && skipTransientField) { - continue; - } - if ((responseFieldToUnderline && isResp) || (requestFieldToUnderline && !isResp)) { - fieldName = StringUtil.camelToUnderline(fieldName); - } - String typeSimpleName = field.getType().getSimpleName(); - String fieldGicName = field.getType().getGenericCanonicalName(); - List javaAnnotations = docField.getAnnotations(); - - Map tagsMap = DocUtil.getFieldTagsValue(field, docField); - String since = DocGlobalConstants.DEFAULT_VERSION;//since tag value - if (!isResp) { - pre: - if (tagsMap.containsKey(DocTags.IGNORE)) { - continue out; - } else if (tagsMap.containsKey(DocTags.SINCE)) { - since = tagsMap.get(DocTags.SINCE); - } - } else { - if (tagsMap.containsKey(DocTags.SINCE)) { - since = tagsMap.get(DocTags.SINCE); - } - } - - boolean strRequired = false; - int annotationCounter = 0; - - an: - for (JavaAnnotation annotation : javaAnnotations) { - String simpleAnnotationName = annotation.getType().getValue(); - if (DocAnnotationConstants.SHORT_JSON_IGNORE.equals(simpleAnnotationName)) { - continue out; - } else if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(simpleAnnotationName)) { - if (null != annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP)) { - if (Boolean.FALSE.toString().equals(annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP).toString())) { - continue out; - } - } else if (null != annotation.getProperty(DocAnnotationConstants.NAME_PROP)) { - fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.NAME_PROP).toString()); - } - } else if (DocAnnotationConstants.SHORT_JSON_PROPERTY.equals(simpleAnnotationName)) { - if (null != annotation.getProperty(DocAnnotationConstants.VALUE_PROP)) { - fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.VALUE_PROP).toString()); - } - } else if (ValidatorAnnotations.NULL.equals(simpleAnnotationName) && !isResp) { - List groupClassList = JavaClassUtil.getParamGroupJavaClass(annotation); - for (String javaClass : groupClassList) { - if (groupClasses.contains(javaClass)) { - strRequired = false; - break an; - } - } - } else if (JavaClassValidateUtil.isJSR303Required(simpleAnnotationName) && !isResp) { - annotationCounter++; - boolean hasGroup = false; - List groupClassList = JavaClassUtil.getParamGroupJavaClass(annotation); - for (String javaClass : groupClassList) { - if (groupClasses.contains(javaClass)) { - hasGroup = true; - } - } - if (hasGroup) { - strRequired = true; - } else if (CollectionUtil.isEmpty(groupClasses)) { - strRequired = true; - } - break an; - } - } - if (annotationCounter < 1) { - doc: - if (tagsMap.containsKey(DocTags.REQUIRED)) { - strRequired = true; - break doc; - } - } - //cover comment - CustomRespField customResponseField = responseFieldMap.get(field.getName()); - String comment; - if (null != customResponseField && StringUtil.isNotEmpty(customResponseField.getDesc())) { - comment = customResponseField.getDesc(); - } else { - comment = docField.getComment(); - } - if (StringUtil.isNotEmpty(comment)) { - comment = DocUtil.replaceNewLineToHtmlBr(comment); - } - if (JavaClassValidateUtil.isPrimitive(subTypeName)) { - ApiParam param = ApiParam.of().setField(pre + fieldName); - param.setPid(pid); - String processedType = isShowJavaType ? typeSimpleName : DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); - param.setType(processedType); - if (StringUtil.isNotEmpty(comment)) { - commonHandleParam(paramList, param, isRequired, comment, since, strRequired); - } else { - commonHandleParam(paramList, param, isRequired, NO_COMMENTS_FOUND, since, strRequired); - } - } else { - ApiParam param = ApiParam.of().setField(pre + fieldName); - JavaClass javaClass = projectBuilder.getJavaProjectBuilder().getClassByName(subTypeName); - String enumComments = javaClass.getComment(); - if (javaClass.isEnum()) { - if (projectBuilder.getApiConfig().getInlineEnum()) { - ApiDataDictionary dataDictionary = projectBuilder.getApiConfig().getDataDictionary(javaClass.getSimpleName()); - if (dataDictionary == null) { - comment = comment + JavaClassUtil.getEnumParams(javaClass); - } else { - comment = comment + "(enum:" + dictionaryListComment(dataDictionary) + ")"; - } - } else { - enumComments = DocUtil.replaceNewLineToHtmlBr(enumComments); - comment = comment + "
" + JavaClassUtil.getEnumParams(javaClass) + "
"; - if (enumComments != null) { - comment = comment + "(See: " + enumComments + ")"; - } - comment = StringUtil.removeQuotes(comment); - - } - param.setType(DocGlobalConstants.ENUM); - } - //如果是文件 - if(typeSimpleName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)){ - param.setType("file"); - } - //如果已经设置返回类型 不需要再次设置 - if (param.getType() == null) { - String processedType; - if (typeSimpleName.length() == 1) { - processedType = DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); - } else { - processedType = isShowJavaType ? typeSimpleName : DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); - } - param.setType(processedType); - } - if (!isResp && javaClass.isEnum()) { - List methods = javaClass.getMethods(); - int index = 0; - - enumOut: - for (JavaMethod method : methods) { - List javaAnnotationList = method.getAnnotations(); - for (JavaAnnotation annotation : javaAnnotationList) { - if (annotation.getType().getValue().contains("JsonValue")) { - break enumOut; - } - } - if (CollectionUtil.isEmpty(javaAnnotations) && index < 1) { - break enumOut; - } - index++; - } - param.setType(DocGlobalConstants.ENUM); - } - - if (StringUtil.isNotEmpty(comment)) { - commonHandleParam(paramList, param, isRequired, comment, since, strRequired); - } else { - commonHandleParam(paramList, param, isRequired, NO_COMMENTS_FOUND, since, strRequired); - } - StringBuilder preBuilder = new StringBuilder(); - for (int j = 0; j < level; j++) { - preBuilder.append(DocGlobalConstants.FIELD_SPACE); - } - preBuilder.append("└─"); - int fieldPid = paramList.size(); - if (JavaClassValidateUtil.isMap(subTypeName)) { - String gNameTemp = field.getType().getGenericCanonicalName(); - if (JavaClassValidateUtil.isMap(gNameTemp)) { - ApiParam param1 = ApiParam.of().setField(preBuilder.toString() + "any object") - .setId(paramList.size()+1).setPid(fieldPid) - .setType("object").setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION); - paramList.add(param1); - continue; - } - String valType = DocClassUtil.getMapKeyValueType(gNameTemp)[1]; - if (!JavaClassValidateUtil.isPrimitive(valType)) { - if (valType.length() == 1) { - String gicName = genericMap.get(valType); - if (!JavaClassValidateUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) { - paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } else { - paramList.addAll(buildParams(valType, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } - } else if (JavaClassValidateUtil.isCollection(subTypeName)) { - String gNameTemp = field.getType().getGenericCanonicalName(); - if (globGicName.length > 0 && "java.util.List".equals(gNameTemp)) { - gNameTemp = gNameTemp + ""; - } - String[] gNameArr = DocClassUtil.getSimpleGicName(gNameTemp); - if (gNameArr.length == 0) { - continue out; - } - String gName = DocClassUtil.getSimpleGicName(gNameTemp)[0]; - if (!JavaClassValidateUtil.isPrimitive(gName)) { - if (!simpleName.equals(gName) && !gName.equals(simpleName)) { - if (gName.length() == 1) { - int len = globGicName.length; - if (len > 0) { - String gicName = genericMap.get(gName) != null ? genericMap.get(gName) : globGicName[0]; - if (!JavaClassValidateUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) { - paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } - } else { - paramList.addAll(buildParams(gName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } - } - } else - if (subTypeName.length() == 1 || DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) { - if (isGenerics && DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) { - ApiParam param1 = ApiParam.of().setField(preBuilder.toString() + "any object") - .setId(paramList.size()) - .setType("object").setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION); - paramList.add(param1); - } else if (!simpleName.equals(className)) { - if (globGicName.length > 0) { - String gicName = genericMap.get(subTypeName) != null ? genericMap.get(subTypeName) : globGicName[0]; - String simple = DocClassUtil.getSimpleName(gicName); - if (JavaClassValidateUtil.isPrimitive(simple)) { - //do nothing - } else if (gicName.contains("<")) { - if (JavaClassValidateUtil.isCollection(simple)) { - String gName = DocClassUtil.getSimpleGicName(gicName)[0]; - if (!JavaClassValidateUtil.isPrimitive(gName)) { - paramList.addAll(buildParams(gName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } else if (JavaClassValidateUtil.isMap(simple)) { - String valType = DocClassUtil.getMapKeyValueType(gicName)[1]; - if (!JavaClassValidateUtil.isPrimitive(valType)) { - paramList.addAll(buildParams(valType, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } else { - paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } else { - paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } else { - paramList.addAll(buildParams(subTypeName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } - } else if (JavaClassValidateUtil.isArray(subTypeName)) { - fieldGicName = fieldGicName.substring(0, fieldGicName.indexOf("[")); - if (className.equals(fieldGicName)) { - //do nothing - } else if (!JavaClassValidateUtil.isPrimitive(fieldGicName)) { - paramList.addAll(buildParams(fieldGicName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } else if (simpleName.equals(subTypeName)) { - //do nothing - } else { - if (!javaClass.isEnum()) { - paramList.addAll(buildParams(fieldGicName, preBuilder.toString(), nextLevel, isRequired, - responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); - } - } - } - } - } - return paramList; - } - - public static String dictionaryListComment(ApiDataDictionary dictionary) { - List enumDataDict = dictionary.getEnumDataDict(); - return enumDataDict.stream().map(apiDataDictionary -> - apiDataDictionary.getValue() + ":" + apiDataDictionary.getDesc() - ).collect(Collectors.joining(",")); - } - - public static List primitiveReturnRespComment(String typeName) { - StringBuilder comments = new StringBuilder(); - comments.append("The api directly returns the ").append(typeName).append(" type value."); - ApiParam apiParam = ApiParam.of().setField("No field") - .setType(typeName).setDesc(comments.toString()).setVersion(DocGlobalConstants.DEFAULT_VERSION); - List paramList = new ArrayList<>(); - paramList.add(apiParam); - return paramList; - } - - private static void commonHandleParam(List paramList, ApiParam param, String isRequired, String comment, String since, boolean strRequired) { - if (StringUtil.isEmpty(isRequired)) { - param.setDesc(comment).setVersion(since); - } else { - param.setDesc(comment).setVersion(since).setRequired(strRequired); - } - param.setId(paramList.size() + param.getPid() + 1); - paramList.add(param); - } -} +/* + * smart-doc https://github.com/shalousun/smart-doc + * + * Copyright (C) 2018-2020 smart-doc + * + * 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 com.power.doc.helper; + +import com.power.common.model.EnumDictionary; +import com.power.common.util.CollectionUtil; +import com.power.common.util.StringUtil; +import com.power.doc.builder.ProjectDocConfigBuilder; +import com.power.doc.constants.DocAnnotationConstants; +import com.power.doc.constants.DocGlobalConstants; +import com.power.doc.constants.DocTags; +import com.power.doc.constants.ValidatorAnnotations; +import com.power.doc.model.*; +import com.power.doc.utils.*; +import com.thoughtworks.qdox.model.*; + +import java.util.*; +import java.util.stream.Collectors; + +import static com.power.doc.constants.DocGlobalConstants.NO_COMMENTS_FOUND; + +/** + * @author yu 2019/12/21. + */ +public class ParamsBuildHelper { + + public static List buildParams(String className, String pre, int level, String isRequired, + Map responseFieldMap, boolean isResp, + Map registryClasses, ProjectDocConfigBuilder projectBuilder, + List groupClasses, int pid) { + //存储泛型所对应的实体类 + Map genericMap = new HashMap<>(10); + + if (StringUtil.isEmpty(className)) { + throw new RuntimeException("Class name can't be null or empty."); + } + ApiConfig apiConfig = projectBuilder.getApiConfig(); + int nextLevel = level + 1; + // Check circular reference + List paramList = new ArrayList<>(); + if (level > apiConfig.getRecursionLimit()) { + return paramList; + } + if (registryClasses.containsKey(className) && level > registryClasses.size()) { + return paramList; + } + boolean skipTransientField = apiConfig.isSkipTransientField(); + boolean isShowJavaType = projectBuilder.getApiConfig().getShowJavaType(); + boolean requestFieldToUnderline = projectBuilder.getApiConfig().isRequestFieldToUnderline(); + boolean responseFieldToUnderline = projectBuilder.getApiConfig().isResponseFieldToUnderline(); + // Registry class + registryClasses.put(className, className); + String simpleName = DocClassUtil.getSimpleName(className); + String[] globGicName = DocClassUtil.getSimpleGicName(className); + JavaClass cls = projectBuilder.getClassByName(simpleName); + //如果存在泛型 则将泛型与类名的对应关系存起来 + if (cls != null && null != cls.getTypeParameters()) { + List> variables = cls.getTypeParameters(); + for (int i = 0; i < cls.getTypeParameters().size() && i fields = JavaClassUtil.getFields(cls, 0, new HashSet<>()); + if (JavaClassValidateUtil.isPrimitive(simpleName)) { + String processedType = isShowJavaType ? simpleName : DocClassUtil.processTypeNameForParams(simpleName.toLowerCase()); + paramList.addAll(primitiveReturnRespComment(processedType)); + } else if (JavaClassValidateUtil.isCollection(simpleName) || JavaClassValidateUtil.isArray(simpleName)) { + if (!JavaClassValidateUtil.isCollection(globGicName[0])) { + String gicName = globGicName[0]; + if (JavaClassValidateUtil.isArray(gicName)) { + gicName = gicName.substring(0, gicName.indexOf("[")); + } + paramList.addAll(buildParams(gicName, pre, nextLevel, isRequired, responseFieldMap, isResp, + registryClasses, projectBuilder, groupClasses, pid)); + } + } else if (JavaClassValidateUtil.isMap(simpleName)) { + if (globGicName.length == 2) { + paramList.addAll(buildParams(globGicName[1], pre, nextLevel, isRequired, responseFieldMap, isResp, + registryClasses, projectBuilder, groupClasses, pid)); + } + } else if (DocGlobalConstants.JAVA_OBJECT_FULLY.equals(className)) { + ApiParam param = ApiParam.of().setField(pre + "any object").setType("object").setPid(pid); + if (StringUtil.isEmpty(isRequired)) { + param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION); + } else { + param.setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setRequired(false).setVersion(DocGlobalConstants.DEFAULT_VERSION); + } + paramList.add(param); + } +// if (className.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)) { +// ApiParam param = ApiParam.of().setField("").setType("file") +// .setPid(pid) +// .setDesc("comment").setRequired(true).setVersion(DocGlobalConstants.DEFAULT_VERSION); +// paramList.add(param); +// } + else { + boolean isGenerics = JavaFieldUtil.checkGenerics(fields); + out: + for (DocJavaField docField : fields) { + JavaField field = docField.getJavaField(); + String fieldName = field.getName(); + String subTypeName = field.getType().getFullyQualifiedName(); + if (field.isStatic() || "this$0".equals(fieldName) || + JavaClassValidateUtil.isIgnoreFieldTypes(subTypeName)) { + continue; + } + if (field.isTransient() && skipTransientField) { + continue; + } + if ((responseFieldToUnderline && isResp) || (requestFieldToUnderline && !isResp)) { + fieldName = StringUtil.camelToUnderline(fieldName); + } + String typeSimpleName = field.getType().getSimpleName(); + String fieldGicName = field.getType().getGenericCanonicalName(); + List javaAnnotations = docField.getAnnotations(); + + Map tagsMap = DocUtil.getFieldTagsValue(field, docField); + String since = DocGlobalConstants.DEFAULT_VERSION;//since tag value + if (!isResp) { + pre: + if (tagsMap.containsKey(DocTags.IGNORE)) { + continue out; + } else if (tagsMap.containsKey(DocTags.SINCE)) { + since = tagsMap.get(DocTags.SINCE); + } + } else { + if (tagsMap.containsKey(DocTags.SINCE)) { + since = tagsMap.get(DocTags.SINCE); + } + } + + boolean strRequired = false; + int annotationCounter = 0; + + an: + for (JavaAnnotation annotation : javaAnnotations) { + String simpleAnnotationName = annotation.getType().getValue(); + if (DocAnnotationConstants.SHORT_JSON_IGNORE.equals(simpleAnnotationName)) { + continue out; + } else if (DocAnnotationConstants.SHORT_JSON_FIELD.equals(simpleAnnotationName)) { + if (null != annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP)) { + if (Boolean.FALSE.toString().equals(annotation.getProperty(DocAnnotationConstants.SERIALIZE_PROP).toString())) { + continue out; + } + } else if (null != annotation.getProperty(DocAnnotationConstants.NAME_PROP)) { + fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.NAME_PROP).toString()); + } + } else if (DocAnnotationConstants.SHORT_JSON_PROPERTY.equals(simpleAnnotationName)) { + if (null != annotation.getProperty(DocAnnotationConstants.VALUE_PROP)) { + fieldName = StringUtil.removeQuotes(annotation.getProperty(DocAnnotationConstants.VALUE_PROP).toString()); + } + } else if (ValidatorAnnotations.NULL.equals(simpleAnnotationName) && !isResp) { + List groupClassList = JavaClassUtil.getParamGroupJavaClass(annotation); + for (String javaClass : groupClassList) { + if (groupClasses.contains(javaClass)) { + strRequired = false; + break an; + } + } + } else if (JavaClassValidateUtil.isJSR303Required(simpleAnnotationName) && !isResp) { + annotationCounter++; + boolean hasGroup = false; + List groupClassList = JavaClassUtil.getParamGroupJavaClass(annotation); + for (String javaClass : groupClassList) { + if (groupClasses.contains(javaClass)) { + hasGroup = true; + } + } + if (hasGroup) { + strRequired = true; + } else if (CollectionUtil.isEmpty(groupClasses)) { + strRequired = true; + } + break an; + } + } + if (annotationCounter < 1) { + doc: + if (tagsMap.containsKey(DocTags.REQUIRED)) { + strRequired = true; + break doc; + } + } + //cover comment + CustomRespField customResponseField = responseFieldMap.get(field.getName()); + String comment; + if (null != customResponseField && StringUtil.isNotEmpty(customResponseField.getDesc())) { + comment = customResponseField.getDesc(); + } else { + comment = docField.getComment(); + } + if (StringUtil.isNotEmpty(comment)) { + comment = DocUtil.replaceNewLineToHtmlBr(comment); + } + if (JavaClassValidateUtil.isPrimitive(subTypeName)) { + ApiParam param = ApiParam.of().setField(pre + fieldName); + param.setPid(pid); + String processedType = isShowJavaType ? typeSimpleName : DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); + param.setType(processedType); + if (StringUtil.isNotEmpty(comment)) { + commonHandleParam(paramList, param, isRequired, comment, since, strRequired); + } else { + commonHandleParam(paramList, param, isRequired, NO_COMMENTS_FOUND, since, strRequired); + } + } else { + ApiParam param = ApiParam.of().setField(pre + fieldName).setPid(pid); + JavaClass javaClass = projectBuilder.getJavaProjectBuilder().getClassByName(subTypeName); + String enumComments = javaClass.getComment(); + if (javaClass.isEnum()) { + if (projectBuilder.getApiConfig().getInlineEnum()) { + ApiDataDictionary dataDictionary = projectBuilder.getApiConfig().getDataDictionary(javaClass.getSimpleName()); + if (dataDictionary == null) { + comment = comment + JavaClassUtil.getEnumParams(javaClass); + } else { + comment = comment + "(enum:" + dictionaryListComment(dataDictionary) + ")"; + } + } else { + enumComments = DocUtil.replaceNewLineToHtmlBr(enumComments); + comment = comment + "
" + JavaClassUtil.getEnumParams(javaClass) + "
"; + if (enumComments != null) { + comment = comment + "(See: " + enumComments + ")"; + } + comment = StringUtil.removeQuotes(comment); + + } + param.setType(DocGlobalConstants.ENUM); + } + //如果是文件 + if(typeSimpleName.contains(DocGlobalConstants.MULTIPART_FILE_FULLY)){ + param.setType("file"); + } + //如果已经设置返回类型 不需要再次设置 + if (param.getType() == null) { + String processedType; + if (typeSimpleName.length() == 1) { + processedType = DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); + } else { + processedType = isShowJavaType ? typeSimpleName : DocClassUtil.processTypeNameForParams(typeSimpleName.toLowerCase()); + } + param.setType(processedType); + } + if (!isResp && javaClass.isEnum()) { + List methods = javaClass.getMethods(); + int index = 0; + + enumOut: + for (JavaMethod method : methods) { + List javaAnnotationList = method.getAnnotations(); + for (JavaAnnotation annotation : javaAnnotationList) { + if (annotation.getType().getValue().contains("JsonValue")) { + break enumOut; + } + } + if (CollectionUtil.isEmpty(javaAnnotations) && index < 1) { + break enumOut; + } + index++; + } + param.setType(DocGlobalConstants.ENUM); + } + + if (StringUtil.isNotEmpty(comment)) { + commonHandleParam(paramList, param, isRequired, comment, since, strRequired); + } else { + commonHandleParam(paramList, param, isRequired, NO_COMMENTS_FOUND, since, strRequired); + } + StringBuilder preBuilder = new StringBuilder(); + for (int j = 0; j < level; j++) { + preBuilder.append(DocGlobalConstants.FIELD_SPACE); + } + preBuilder.append("└─"); + int fieldPid = paramList.size()+pid; + if (JavaClassValidateUtil.isMap(subTypeName)) { + String gNameTemp = field.getType().getGenericCanonicalName(); + if (JavaClassValidateUtil.isMap(gNameTemp)) { + ApiParam param1 = ApiParam.of().setField(preBuilder.toString() + "any object") + .setId(paramList.size()+1).setPid(fieldPid) + .setType("object").setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION); + paramList.add(param1); + continue; + } + String valType = DocClassUtil.getMapKeyValueType(gNameTemp)[1]; + if (!JavaClassValidateUtil.isPrimitive(valType)) { + if (valType.length() == 1) { + String gicName = genericMap.get(valType); + if (!JavaClassValidateUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) { + paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } else { + paramList.addAll(buildParams(valType, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } + } else if (JavaClassValidateUtil.isCollection(subTypeName)) { + String gNameTemp = field.getType().getGenericCanonicalName(); + if (globGicName.length > 0 && "java.util.List".equals(gNameTemp)) { + gNameTemp = gNameTemp + ""; + } + String[] gNameArr = DocClassUtil.getSimpleGicName(gNameTemp); + if (gNameArr.length == 0) { + continue out; + } + String gName = DocClassUtil.getSimpleGicName(gNameTemp)[0]; + if (!JavaClassValidateUtil.isPrimitive(gName)) { + if (!simpleName.equals(gName) && !gName.equals(simpleName)) { + if (gName.length() == 1) { + int len = globGicName.length; + if (len > 0) { + String gicName = genericMap.get(gName) != null ? genericMap.get(gName) : globGicName[0]; + if (!JavaClassValidateUtil.isPrimitive(gicName) && !simpleName.equals(gicName)) { + paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } + } else { + paramList.addAll(buildParams(gName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } + } + } else + if (subTypeName.length() == 1 || DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) { + if (isGenerics && DocGlobalConstants.JAVA_OBJECT_FULLY.equals(subTypeName)) { + ApiParam param1 = ApiParam.of().setField(preBuilder.toString() + "any object") + .setId(paramList.size()) + .setType("object").setDesc(DocGlobalConstants.ANY_OBJECT_MSG).setVersion(DocGlobalConstants.DEFAULT_VERSION); + paramList.add(param1); + } else if (!simpleName.equals(className)) { + if (globGicName.length > 0) { + String gicName = genericMap.get(subTypeName) != null ? genericMap.get(subTypeName) : globGicName[0]; + String simple = DocClassUtil.getSimpleName(gicName); + if (JavaClassValidateUtil.isPrimitive(simple)) { + //do nothing + } else if (gicName.contains("<")) { + if (JavaClassValidateUtil.isCollection(simple)) { + String gName = DocClassUtil.getSimpleGicName(gicName)[0]; + if (!JavaClassValidateUtil.isPrimitive(gName)) { + paramList.addAll(buildParams(gName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } else if (JavaClassValidateUtil.isMap(simple)) { + String valType = DocClassUtil.getMapKeyValueType(gicName)[1]; + if (!JavaClassValidateUtil.isPrimitive(valType)) { + paramList.addAll(buildParams(valType, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } else { + paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } else { + paramList.addAll(buildParams(gicName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } else { + paramList.addAll(buildParams(subTypeName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } + } else if (JavaClassValidateUtil.isArray(subTypeName)) { + fieldGicName = fieldGicName.substring(0, fieldGicName.indexOf("[")); + if (className.equals(fieldGicName)) { + //do nothing + } else if (!JavaClassValidateUtil.isPrimitive(fieldGicName)) { + paramList.addAll(buildParams(fieldGicName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } else if (simpleName.equals(subTypeName)) { + //do nothing + } else { + if (!javaClass.isEnum()) { + paramList.addAll(buildParams(fieldGicName, preBuilder.toString(), nextLevel, isRequired, + responseFieldMap, isResp, registryClasses, projectBuilder, groupClasses, fieldPid)); + } + } + } + } + } + return paramList; + } + + public static String dictionaryListComment(ApiDataDictionary dictionary) { + List enumDataDict = dictionary.getEnumDataDict(); + return enumDataDict.stream().map(apiDataDictionary -> + apiDataDictionary.getValue() + ":" + apiDataDictionary.getDesc() + ).collect(Collectors.joining(",")); + } + + public static List primitiveReturnRespComment(String typeName) { + StringBuilder comments = new StringBuilder(); + comments.append("The api directly returns the ").append(typeName).append(" type value."); + ApiParam apiParam = ApiParam.of().setField("No field") + .setType(typeName).setDesc(comments.toString()).setVersion(DocGlobalConstants.DEFAULT_VERSION); + List paramList = new ArrayList<>(); + paramList.add(apiParam); + return paramList; + } + + private static void commonHandleParam(List paramList, ApiParam param, String isRequired, String comment, String since, boolean strRequired) { + if (StringUtil.isEmpty(isRequired)) { + param.setDesc(comment).setVersion(since); + } else { + param.setDesc(comment).setVersion(since).setRequired(strRequired); + } + param.setId(paramList.size() + param.getPid() + 1); + paramList.add(param); + } +} diff --git a/src/main/java/com/power/doc/model/ApiParam.java b/src/main/java/com/power/doc/model/ApiParam.java index 0137d45..7844f46 100644 --- a/src/main/java/com/power/doc/model/ApiParam.java +++ b/src/main/java/com/power/doc/model/ApiParam.java @@ -1,157 +1,162 @@ -/* - * smart-doc - * - * Copyright (C) 2018-2020 smart-doc - * - * 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 com.power.doc.model; - -import java.util.List; - -/** - * @author yu 2019/9/27. - */ -public class ApiParam { - - /** - * field id - */ - private int id = 1; - - /** - * field - */ - private String field; - - /** - * field type - */ - private String type; - - /** - * description - */ - private String desc; - - /** - * require flag - */ - private boolean required; - - /** - * version - */ - private String version; - - /** - * field pid - */ - private int pid; - /** - * PathVariableParams flag - */ - private boolean isPathParams; - - private List children; - - public static ApiParam of(){ - return new ApiParam(); - } - - public String getField() { - return field; - } - - public ApiParam setField(String field) { - this.field = field; - return this; - } - - public String getType() { - return type; - } - - public ApiParam setType(String type) { - this.type = type; - return this; - } - - public String getDesc() { - return desc; - } - - public ApiParam setDesc(String desc) { - this.desc = desc; - return this; - } - - public boolean isRequired() { - return required; - } - - public ApiParam setRequired(boolean required) { - this.required = required; - return this; - } - - public String getVersion() { - return version; - } - - public ApiParam setVersion(String version) { - this.version = version; - return this; - } - - public int getId() { - return id; - } - - public ApiParam setId(int id) { - this.id = id; - return this; - } - - public int getPid() { - return pid; - } - - public ApiParam setPid(int pid) { - this.pid = pid; - return this; - } - - public List getChildren() { - return children; - } - - public boolean isPathParams() { - return isPathParams; - } - - public ApiParam setPathParams(boolean pathParams) { - isPathParams = pathParams; - return this; - } - - public ApiParam setChildren(List children) { - this.children = children; - return this; - } -} +/* + * smart-doc + * + * Copyright (C) 2018-2020 smart-doc + * + * 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 com.power.doc.model; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author yu 2019/9/27. + */ +public class ApiParam { + + /** + * field id + */ + private int id = 1; + + /** + * field + */ + private String field; + + /** + * field type + */ + private String type; + + /** + * description + */ + private String desc; + + /** + * require flag + */ + private boolean required; + + /** + * version + */ + private String version; + + /** + * field pid + */ + private int pid; + + /** + * PathVariableParams flag + */ + private boolean isPathParams; + + /** + * children params + */ + private List children; + + public static ApiParam of(){ + return new ApiParam(); + } + + public String getField() { + return field; + } + + public ApiParam setField(String field) { + this.field = field; + return this; + } + + public String getType() { + return type; + } + + public ApiParam setType(String type) { + this.type = type; + return this; + } + + public String getDesc() { + return desc; + } + + public ApiParam setDesc(String desc) { + this.desc = desc; + return this; + } + + public boolean isRequired() { + return required; + } + + public ApiParam setRequired(boolean required) { + this.required = required; + return this; + } + + public String getVersion() { + return version; + } + + public ApiParam setVersion(String version) { + this.version = version; + return this; + } + + public int getId() { + return id; + } + + public ApiParam setId(int id) { + this.id = id; + return this; + } + + public int getPid() { + return pid; + } + + public ApiParam setPid(int pid) { + this.pid = pid; + return this; + } + + public List getChildren() { + return children; + } + + public boolean isPathParams() { + return isPathParams; + } + + public ApiParam setPathParams(boolean pathParams) { + isPathParams = pathParams; + return this; + } + + public ApiParam setChildren(List children) { + this.children = children; + return this; + } +} diff --git a/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java b/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java index d3d91c2..284b3cd 100644 --- a/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java +++ b/src/main/java/com/power/doc/template/SpringBootDocBuildTemplate.java @@ -22,7 +22,10 @@ */ package com.power.doc.template; -import com.power.common.util.*; +import com.power.common.util.JsonFormatUtil; +import com.power.common.util.RandomUtil; +import com.power.common.util.StringUtil; +import com.power.common.util.UrlUtil; import com.power.doc.builder.ProjectDocConfigBuilder; import com.power.doc.constants.*; import com.power.doc.handler.SpringMVCRequestHeaderHandler; @@ -44,7 +47,6 @@ import java.util.stream.Stream; import static com.power.doc.constants.DocGlobalConstants.FILE_CONTENT_TYPE; import static com.power.doc.constants.DocGlobalConstants.JSON_CONTENT_TYPE; import static com.power.doc.constants.DocTags.IGNORE; -import static com.power.doc.constants.DocTags.PARAM; /** * @author yu 2019/12/21. @@ -90,8 +92,8 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { } @Override - public boolean ignoreReturnObject(String typeName,List ignoreParams) { - if (JavaClassValidateUtil.isMvcIgnoreParams(typeName,ignoreParams)) { + public boolean ignoreReturnObject(String typeName, List ignoreParams) { + if (JavaClassValidateUtil.isMvcIgnoreParams(typeName, ignoreParams)) { return DocGlobalConstants.MODE_AND_VIEW_FULLY.equals(typeName); } return false; @@ -165,6 +167,17 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { requestParams = ApiParamTreeUtil.apiParamToTree(requestParams); } apiMethodDoc.setRequestParams(requestParams); + List allApiReqHeaders; + if (this.headers != null) { + allApiReqHeaders = Stream.of(this.headers, apiReqHeaders) + .flatMap(Collection::stream).distinct().collect(Collectors.toList()); + } else { + allApiReqHeaders = apiReqHeaders; + } + //reduce create in template + apiMethodDoc.setHeaders(this.createDocRenderHeaders(allApiReqHeaders, apiConfig.isAdoc())); + apiMethodDoc.setRequestHeaders(allApiReqHeaders); + // build request json ApiRequestExample requestExample = buildReqJson(method, apiMethodDoc, requestMapping.getMethodType(), projectBuilder); @@ -180,16 +193,6 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { responseParams = ApiParamTreeUtil.apiParamToTree(responseParams); } apiMethodDoc.setResponseParams(responseParams); - List allApiReqHeaders; - if (this.headers != null) { - allApiReqHeaders = Stream.of(this.headers, apiReqHeaders) - .flatMap(Collection::stream).distinct().collect(Collectors.toList()); - } else { - allApiReqHeaders = apiReqHeaders; - } - //reduce create in template - apiMethodDoc.setHeaders(this.createDocRenderHeaders(allApiReqHeaders, apiConfig.isAdoc())); - apiMethodDoc.setRequestHeaders(allApiReqHeaders); methodDocList.add(apiMethodDoc); } } @@ -199,9 +202,18 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { private ApiRequestExample buildReqJson(JavaMethod method, ApiMethodDoc apiMethodDoc, String methodType, ProjectDocConfigBuilder configBuilder) { List parameterList = method.getParameters(); - if (parameterList.size() < 1) { - return ApiRequestExample.builder().setUrl(apiMethodDoc.getUrl()); + List reqHeaderList = apiMethodDoc.getRequestHeaders(); + StringBuilder header = new StringBuilder(reqHeaderList.size()); + for (ApiReqHeader reqHeader : reqHeaderList) { + header.append(" -H ").append("'").append(reqHeader.getName()) + .append(":").append(reqHeader.getValue()).append("'"); } + if (parameterList.size() < 1) { + String format = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType, + header.toString(), apiMethodDoc.getUrl()); + return ApiRequestExample.builder().setUrl(apiMethodDoc.getUrl()).setExampleBody(format); + } + Map constantsMap = configBuilder.getConstantsMap(); boolean requestFieldToUnderline = configBuilder.getApiConfig().isRequestFieldToUnderline(); Map replacementMap = configBuilder.getReplaceClassMap(); @@ -210,7 +222,6 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { List springMvcRequestAnnotations = SpringMvcRequestAnnotationsEnum.listSpringMvcRequestAnnotations(); List formDataList = new ArrayList<>(); ApiRequestExample requestExample = ApiRequestExample.builder(); - Set jsonParamSet = this.jsonParamSet(parameterList); out: for (JavaParameter parameter : parameterList) { JavaType javaType = parameter.getType(); @@ -218,12 +229,9 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { String typeName = javaType.getFullyQualifiedName(); String gicTypeName = javaType.getGenericCanonicalName(); String rewriteClassName = null; - if (jsonParamSet.size() > 0 && !jsonParamSet.contains(paramName)) { - continue; - } String commentClass = paramsComments.get(paramName); //ignore request params - if(Objects.nonNull(commentClass) && commentClass.contains(IGNORE)){ + if (Objects.nonNull(commentClass) && commentClass.contains(IGNORE)) { continue; } if (Objects.nonNull(commentClass) && !DocGlobalConstants.NO_COMMENTS_FOUND.equals(commentClass)) { @@ -237,7 +245,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { gicTypeName = rewriteClassName; typeName = DocClassUtil.getSimpleName(rewriteClassName); } - if (JavaClassValidateUtil.isMvcIgnoreParams(typeName,configBuilder.getApiConfig().getIgnoreRequestParams())) { + if (JavaClassValidateUtil.isMvcIgnoreParams(typeName, configBuilder.getApiConfig().getIgnoreRequestParams())) { continue; } String simpleTypeName = javaType.getValue().toLowerCase(); @@ -380,18 +388,19 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { body = StringUtil.removeQuotes(body); url = apiMethodDoc.getServerUrl() + "/" + path; url = UrlUtil.simplifyUrl(url); + String format = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType, header.toString(), url); if (requestExample.isJson()) { if (StringUtil.isNotEmpty(requestExample.getJsonBody())) { - exampleBody = String.format(DocGlobalConstants.CURL_POST_PUT_JSON, methodType, url, + exampleBody = String.format(DocGlobalConstants.CURL_POST_PUT_JSON, methodType,header.toString(), url, requestExample.getJsonBody()); } else { - exampleBody = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType, url); + exampleBody = format; } } else { if (StringUtil.isNotEmpty(body)) { - exampleBody = String.format(DocGlobalConstants.CURL_REQUEST_TYPE_DATA, methodType, url, body); + exampleBody = String.format(DocGlobalConstants.CURL_REQUEST_TYPE_DATA, methodType,header.toString(), url, body); } else { - exampleBody = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType, url); + exampleBody = format; } } requestExample.setExampleBody(exampleBody).setUrl(url); @@ -403,7 +412,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { url = StringUtil.removeQuotes(url); url = apiMethodDoc.getServerUrl() + "/" + url; url = UrlUtil.simplifyUrl(url); - exampleBody = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType, url); + exampleBody = String.format(DocGlobalConstants.CURL_REQUEST_TYPE, methodType,header.toString(), url); requestExample.setExampleBody(exampleBody) .setJsonBody(DocGlobalConstants.EMPTY) .setUrl(url); @@ -424,15 +433,11 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { } Map constantsMap = builder.getConstantsMap(); boolean requestFieldToUnderline = builder.getApiConfig().isRequestFieldToUnderline(); - Set jsonParamSet = this.jsonParamSet(parameterList); List paramList = new ArrayList<>(); int requestBodyCounter = 0; out: for (JavaParameter parameter : parameterList) { String paramName = parameter.getName(); - if (jsonParamSet.size() > 0 && !jsonParamSet.contains(paramName)) { - continue; - } String typeName = parameter.getType().getGenericCanonicalName(); String simpleName = parameter.getType().getValue().toLowerCase(); String fullTypeName = parameter.getType().getFullyQualifiedName(); @@ -449,7 +454,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { typeName = rewriteClassName; fullTypeName = DocClassUtil.getSimpleName(rewriteClassName); } - if (JavaClassValidateUtil.isMvcIgnoreParams(typeName,builder.getApiConfig().getIgnoreRequestParams())) { + if (JavaClassValidateUtil.isMvcIgnoreParams(typeName, builder.getApiConfig().getIgnoreRequestParams())) { continue out; } fullTypeName = DocClassUtil.rewriteRequestParam(fullTypeName); @@ -482,7 +487,7 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { } if (SpringMvcAnnotations.REQUEST_PARAM.equals(annotationName) || DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) { - if(DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)){ + if (DocAnnotationConstants.SHORT_PATH_VARIABLE.equals(annotationName)) { isPathVariable = true; } paramName = getParamName(paramName, annotation); @@ -508,8 +513,8 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { } } Boolean required = Boolean.parseBoolean(strRequired); - if(isPathVariable){ - comment = comment +" (This is path param)"; + if (isPathVariable) { + comment = comment + " (This is path param)"; } if (JavaClassValidateUtil.isCollection(fullTypeName) || JavaClassValidateUtil.isArray(fullTypeName)) { String[] gicNameArr = DocClassUtil.getSimpleGicName(typeName); @@ -600,19 +605,4 @@ public class SpringBootDocBuildTemplate implements IDocBuildTemplate { } return false; } - - public Set jsonParamSet(List parameterList) { - Set jsonParamSet = new HashSet<>(); - for (JavaParameter parameter : parameterList) { - String paramName = parameter.getName(); - List annotations = parameter.getAnnotations(); - for (JavaAnnotation annotation : annotations) { - String annotationName = annotation.getType().getValue(); - if (SpringMvcAnnotations.REQUEST_BODY.equals(annotationName)) { - jsonParamSet.add(paramName); - } - } - } - return jsonParamSet; - } } diff --git a/src/main/java/com/power/doc/utils/ApiParamTreeUtil.java b/src/main/java/com/power/doc/utils/ApiParamTreeUtil.java index 89736c0..a0f250b 100644 --- a/src/main/java/com/power/doc/utils/ApiParamTreeUtil.java +++ b/src/main/java/com/power/doc/utils/ApiParamTreeUtil.java @@ -46,6 +46,9 @@ public class ApiParamTreeUtil { childList.add(param); } } + for (ApiParam param : childList) { + param.setChildren(getChild(param.getId(), apiParamList)); + } if (childList.size() == 0) { return null; } diff --git a/src/main/java/com/power/doc/utils/DocClassUtil.java b/src/main/java/com/power/doc/utils/DocClassUtil.java index f95d3bf..6bda8fd 100644 --- a/src/main/java/com/power/doc/utils/DocClassUtil.java +++ b/src/main/java/com/power/doc/utils/DocClassUtil.java @@ -1,254 +1,254 @@ -/* - * smart-doc - * - * Copyright (C) 2018-2020 smart-doc - * - * 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 com.power.doc.utils; - -import com.power.common.util.StringUtil; -import com.power.doc.filter.ReturnTypeProcessor; -import com.power.doc.model.ApiReturn; - -import java.util.ArrayList; -import java.util.List; -import java.util.Stack; - -/** - * Description: - * Doc class handle util - * - * @author yu 2018//14. - */ -public class DocClassUtil { - - - /** - * get class names by generic class name - * - * @param returnType generic class name - * @return array of string - */ - public static String[] getSimpleGicName(String returnType) { - if (returnType.contains("<")) { - String pre = returnType.substring(0, returnType.indexOf("<")); - if (JavaClassValidateUtil.isMap(pre)) { - return getMapKeyValueType(returnType); - } - String type = returnType.substring(returnType.indexOf("<") + 1, returnType.lastIndexOf(">")); - if (JavaClassValidateUtil.isCollection(pre)) { - return type.split(" "); - } - String[] arr = type.split(","); - return classNameFix(arr); - } else { - return returnType.split(" "); - } - } - - /** - * Get a simple type name from a generic class name - * - * @param gicName Generic class name - * @return String - */ - public static String getSimpleName(String gicName) { - if (gicName.contains("<")) { - return gicName.substring(0, gicName.indexOf("<")); - } else { - return gicName; - } - } - - /** - * Automatic repair of generic split class names - * - * @param arr arr of class name - * @return array of String - */ - private static String[] classNameFix(String[] arr) { - List classes = new ArrayList<>(); - List indexList = new ArrayList<>(); - int globIndex = 0; - int length = arr.length; - for (int i = 0; i < length; i++) { - if (classes.size() > 0) { - int index = classes.size() - 1; - if (!isClassName(classes.get(index))) { - globIndex = globIndex + 1; - if (globIndex < length) { - indexList.add(globIndex); - String className = classes.get(index) + "," + arr[globIndex]; - classes.set(index, className); - } - } else { - globIndex = globIndex + 1; - if (globIndex < length) { - if (isClassName(arr[globIndex])) { - indexList.add(globIndex); - classes.add(arr[globIndex]); - } else { - if (!indexList.contains(globIndex) && !indexList.contains(globIndex + 1)) { - indexList.add(globIndex); - classes.add(arr[globIndex] + "," + arr[globIndex + 1]); - globIndex = globIndex + 1; - indexList.add(globIndex); - } - } - } - } - } else { - if (isClassName(arr[i])) { - indexList.add(i); - classes.add(arr[i]); - } else { - if (!indexList.contains(i) && !indexList.contains(i + 1)) { - globIndex = i + 1; - classes.add(arr[i] + "," + arr[globIndex]); - indexList.add(i); - indexList.add(i + 1); - } - } - } - } - return classes.toArray(new String[classes.size()]); - } - - /** - * get map key and value type name populate into array. - * - * @param gName generic class name - * @return array of string - */ - public static String[] getMapKeyValueType(String gName) { - if (gName.contains("<")) { - String[] arr = new String[2]; - String key = gName.substring(gName.indexOf("<") + 1, gName.indexOf(",")); - String value = gName.substring(gName.indexOf(",") + 1, gName.lastIndexOf(">")); - arr[0] = key; - arr[1] = value; - return arr; - } else { - return new String[0]; - } - - } - - /** - * Convert the parameter types exported to the api document - * - * @param javaTypeName java simple typeName - * @return String - */ - public static String processTypeNameForParams(String javaTypeName) { - if (StringUtil.isEmpty(javaTypeName)) { - return "object"; - } - if (javaTypeName.length() == 1) { - return "object"; - } - if (javaTypeName.contains("[]")) { - return "array"; - } - switch (javaTypeName) { - case "java.lang.String": - case "string": - case "char": - case "java.util.Byte": - case "byte": - case "date": - case "localdatetime": - case "localdate": - case "localtime": - case "timestamp": - return "string"; - case "java.util.List": - case "list": - return "array"; - case "java.lang.Integer": - case "integer": - case "int": - return "int32"; - case "short": - case "java.lang.Short": - return "int16"; - case "double": - return "double"; - case "java.lang.Long": - case "long": - return "int64"; - case "java.lang.Float": - case "float": - return "float"; - case "bigdecimal": - case "biginteger": - return "number"; - case "java.lang.Boolean": - case "boolean": - return "boolean"; - case "map": - return "map"; - case "multipartfile": - return "file"; - default: - return "object"; - } - - } - - /** - * process return type - * - * @param fullyName fully name - * @return ApiReturn - */ - public static ApiReturn processReturnType(String fullyName) { - ReturnTypeProcessor processor = new ReturnTypeProcessor(); - processor.setTypeName(fullyName); - return processor.process(); - } - - /** - * rewrite request param - * - * @param typeName param type name - * @return String - */ - public static String rewriteRequestParam(String typeName) { - switch (typeName) { - case "org.springframework.data.domain.Pageable": - return "org.springframework.data.domain.PageRequest"; - default: - return typeName; - } - } - - private static boolean isClassName(String className) { - className = className.replaceAll("[^<>]", ""); - Stack stack = new Stack<>(); - for (char c : className.toCharArray()) { - if (c == '<') { - stack.push('>'); - } else if (stack.isEmpty() || c != stack.pop()) { - return false; - } - } - return stack.isEmpty(); - } -} +/* + * smart-doc + * + * Copyright (C) 2018-2020 smart-doc + * + * 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 com.power.doc.utils; + +import com.power.common.util.StringUtil; +import com.power.doc.filter.ReturnTypeProcessor; +import com.power.doc.model.ApiReturn; + +import java.util.ArrayList; +import java.util.List; + +/** + * Description: + * Doc class handle util + * + * @author yu 2018//14. + */ +public class DocClassUtil { + + + /** + * get class names by generic class name + * + * @param returnType generic class name + * @return array of string + */ + public static String[] getSimpleGicName(String returnType) { + if (returnType.contains("<")) { + String pre = returnType.substring(0, returnType.indexOf("<")); + if (JavaClassValidateUtil.isMap(pre)) { + return getMapKeyValueType(returnType); + } + String type = returnType.substring(returnType.indexOf("<") + 1, returnType.lastIndexOf(">")); + if (JavaClassValidateUtil.isCollection(pre)) { + return type.split(" "); + } + String[] arr = type.split(","); + return classNameFix(arr); + } else { + return returnType.split(" "); + } + } + + /** + * Get a simple type name from a generic class name + * + * @param gicName Generic class name + * @return String + */ + public static String getSimpleName(String gicName) { + if (gicName.contains("<")) { + return gicName.substring(0, gicName.indexOf("<")); + } else { + return gicName; + } + } + + /** + * Automatic repair of generic split class names + * + * @param arr arr of class name + * @return array of String + */ + private static String[] classNameFix(String[] arr) { + List classes = new ArrayList<>(); + List indexList = new ArrayList<>(); + int globIndex = 0; + int length = arr.length; + for (int i = 0; i < length; i++) { + if (classes.size() > 0) { + int index = classes.size() - 1; + if (!isClassName(classes.get(index))) { + globIndex = globIndex + 1; + if (globIndex < length) { + indexList.add(globIndex); + String className = classes.get(index) + "," + arr[globIndex]; + classes.set(index, className); + } + } else { + globIndex = globIndex + 1; + if (globIndex < length) { + if (isClassName(arr[globIndex])) { + indexList.add(globIndex); + classes.add(arr[globIndex]); + } else { + if (!indexList.contains(globIndex) && !indexList.contains(globIndex + 1)) { + indexList.add(globIndex); + classes.add(arr[globIndex] + "," + arr[globIndex + 1]); + globIndex = globIndex + 1; + indexList.add(globIndex); + } + } + } + } + } else { + if (isClassName(arr[i])) { + indexList.add(i); + classes.add(arr[i]); + } else { + if (!indexList.contains(i) && !indexList.contains(i + 1)) { + globIndex = i + 1; + classes.add(arr[i] + "," + arr[globIndex]); + indexList.add(i); + indexList.add(i + 1); + } + } + } + } + return classes.toArray(new String[classes.size()]); + } + + /** + * get map key and value type name populate into array. + * + * @param gName generic class name + * @return array of string + */ + public static String[] getMapKeyValueType(String gName) { + if (gName.contains("<")) { + String[] arr = new String[2]; + String key = gName.substring(gName.indexOf("<") + 1, gName.indexOf(",")); + String value = gName.substring(gName.indexOf(",") + 1, gName.lastIndexOf(">")); + arr[0] = key; + arr[1] = value; + return arr; + } else { + return new String[0]; + } + + } + + /** + * Convert the parameter types exported to the api document + * + * @param javaTypeName java simple typeName + * @return String + */ + public static String processTypeNameForParams(String javaTypeName) { + if (StringUtil.isEmpty(javaTypeName)) { + return "object"; + } + if (javaTypeName.length() == 1) { + return "object"; + } + if (javaTypeName.contains("[]")) { + return "array"; + } + switch (javaTypeName) { + case "java.lang.String": + case "string": + case "char": + case "java.util.Byte": + case "byte": + case "date": + case "localdatetime": + case "localdate": + case "localtime": + case "timestamp": + return "string"; + case "java.util.List": + case "list": + return "array"; + case "java.lang.Integer": + case "integer": + case "int": + return "int32"; + case "short": + case "java.lang.Short": + return "int16"; + case "double": + return "double"; + case "java.lang.Long": + case "long": + return "int64"; + case "java.lang.Float": + case "float": + return "float"; + case "bigdecimal": + case "biginteger": + return "number"; + case "java.lang.Boolean": + case "boolean": + return "boolean"; + case "map": + return "map"; + case "multipartfile": + return "file"; + default: + return "object"; + } + + } + + /** + * process return type + * + * @param fullyName fully name + * @return ApiReturn + */ + public static ApiReturn processReturnType(String fullyName) { + ReturnTypeProcessor processor = new ReturnTypeProcessor(); + processor.setTypeName(fullyName); + return processor.process(); + } + + /** + * rewrite request param + * + * @param typeName param type name + * @return String + */ + public static String rewriteRequestParam(String typeName) { + switch (typeName) { + case "org.springframework.data.domain.Pageable": + return "org.springframework.data.domain.PageRequest"; + default: + return typeName; + } + } + + private static boolean isClassName(String className) { + if (StringUtil.isEmpty(className)) { + return false; + } + if (className.contains("<") && !className.contains(">")) { + return false; + } else if (className.contains(">") && !className.contains("<")) { + return false; + } else { + return true; + } + } +} + diff --git a/src/main/java/com/power/doc/utils/Iterables.java b/src/main/java/com/power/doc/utils/Iterables.java new file mode 100644 index 0000000..808ba86 --- /dev/null +++ b/src/main/java/com/power/doc/utils/Iterables.java @@ -0,0 +1,14 @@ +package com.power.doc.utils; + +import java.util.function.BiConsumer; + +public class Iterables { + public static void forEach( + Iterable elements, BiConsumer action) { + if(elements==null||action==null) return; + int index = 0; + for (E element : elements) { + action.accept(index++, element); + } + } +} diff --git a/src/main/java/com/power/doc/utils/JavaClassValidateUtil.java b/src/main/java/com/power/doc/utils/JavaClassValidateUtil.java index 12e10ca..df40bd9 100644 --- a/src/main/java/com/power/doc/utils/JavaClassValidateUtil.java +++ b/src/main/java/com/power/doc/utils/JavaClassValidateUtil.java @@ -1,251 +1,253 @@ -/* - * smart-doc - * - * Copyright (C) 2018-2020 smart-doc - * - * 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 com.power.doc.utils; - -import com.power.common.util.CollectionUtil; - -import java.util.List; -import java.util.Objects; - -/** - * @author yu 2019/12/25. - */ -public class JavaClassValidateUtil { - - /** - * Check if it is the basic data array type of json data - * - * @param type0 java class name - * @return boolean - */ - public static boolean isPrimitiveArray(String type0) { - String type = type0.contains("java.lang") ? type0.substring(type0.lastIndexOf(".") + 1, type0.length()) : type0; - type = type.toLowerCase(); - switch (type) { - case "integer[]": - case "void": - case "int[]": - case "long[]": - case "double[]": - case "float[]": - case "short[]": - case "bigdecimal[]": - case "char[]": - case "string[]": - case "boolean[]": - case "byte[]": - return true; - default: - return false; - } - } - - /** - * Check if it is the basic data type of json data - * - * @param type0 java class name - * @return boolean - */ - public static boolean isPrimitive(String type0) { - if (Objects.isNull(type0)) { - return true; - } - String type = type0.contains("java.lang") ? type0.substring(type0.lastIndexOf(".") + 1, type0.length()) : type0; - type = type.toLowerCase(); - switch (type) { - case "integer": - case "void": - case "int": - case "long": - case "double": - case "float": - case "short": - case "bigdecimal": - case "char": - case "string": - case "boolean": - case "byte": - case "java.sql.timestamp": - case "java.util.date": - case "java.time.localdatetime": - case "java.time.localtime": - case "localdatetime": - case "localdate": - case "java.time.localdate": - case "java.math.bigdecimal": - case "java.math.biginteger": - case "java.io.serializable": - return true; - default: - return false; - } - } - - /** - * validate java collection - * - * @param type java typeName - * @return boolean - */ - public static boolean isCollection(String type) { - switch (type) { - case "java.util.List": - case "java.util.LinkedList": - case "java.util.ArrayList": - case "java.util.Set": - case "java.util.TreeSet": - case "java.util.HashSet": - case "java.util.SortedSet": - case "java.util.Collection": - case "java.util.ArrayDeque": - case "java.util.PriorityQueue": - return true; - default: - return false; - } - } - - /** - * Check if it is an map - * - * @param type java type - * @return boolean - */ - public static boolean isMap(String type) { - switch (type) { - case "java.util.Map": - case "java.util.SortedMap": - case "java.util.TreeMap": - case "java.util.LinkedHashMap": - case "java.util.HashMap": - case "java.util.concurrent.ConcurrentHashMap": - case "java.util.concurrent.ConcurrentMap": - case "java.util.Properties": - case "java.util.Hashtable": - return true; - default: - return false; - } - } - - /** - * check array - * - * @param type type name - * @return boolean - */ - public static boolean isArray(String type) { - return type.contains("[]"); - } - - /** - * check JSR303 - * - * @param annotationSimpleName annotation name - * @return boolean - */ - public static boolean isJSR303Required(String annotationSimpleName) { - switch (annotationSimpleName) { - case "NotNull": - case "NotEmpty": - case "NotBlank": - case "Required": - return true; - default: - return false; - } - } - - - /** - * custom tag - * - * @param tagName custom field tag - * @return boolean - */ - public static boolean isRequiredTag(String tagName) { - switch (tagName) { - case "required": - return true; - default: - return false; - } - } - - /** - * ignore tag request field - * - * @param tagName custom field tag - * @return boolean - */ - public static boolean isIgnoreTag(String tagName) { - switch (tagName) { - case "ignore": - return true; - default: - return false; - } - } - - /** - * ignore param of spring mvc - * - * @param paramType param type name - * @return boolean - */ - public static boolean isMvcIgnoreParams(String paramType,List ignoreParams) { - if(CollectionUtil.isNotEmpty(ignoreParams) && ignoreParams.contains(paramType)){ - return true; - } - switch (paramType) { - case "org.springframework.ui.Model": - case "org.springframework.ui.ModelMap": - case "org.springframework.web.servlet.ModelAndView": - case "org.springframework.validation.BindingResult": - case "javax.servlet.http.HttpServletRequest": - case "org.springframework.web.context.request.WebRequest": - case "javax.servlet.http.HttpSession": - case "javax.servlet.http.HttpServletResponse": - case "org.springframework.web.reactive.function.server.ServerRequest": - return true; - default: - return false; - } - } - - /** - * ignore field type name - * - * @param typeName field type name - * @return String - */ - public static boolean isIgnoreFieldTypes(String typeName) { - switch (typeName) { - case "org.slf4j.Logger": - case "org.apache.ibatis.logging.Log": - return true; - default: - return false; - } - } -} +/* + * smart-doc + * + * Copyright (C) 2018-2020 smart-doc + * + * 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 com.power.doc.utils; + +import com.power.common.util.CollectionUtil; + +import java.util.List; +import java.util.Objects; + +/** + * @author yu 2019/12/25. + */ +public class JavaClassValidateUtil { + + /** + * Check if it is the basic data array type of json data + * + * @param type0 java class name + * @return boolean + */ + public static boolean isPrimitiveArray(String type0) { + String type = type0.contains("java.lang") ? type0.substring(type0.lastIndexOf(".") + 1, type0.length()) : type0; + type = type.toLowerCase(); + switch (type) { + case "integer[]": + case "void": + case "int[]": + case "long[]": + case "double[]": + case "float[]": + case "short[]": + case "bigdecimal[]": + case "char[]": + case "string[]": + case "boolean[]": + case "byte[]": + return true; + default: + return false; + } + } + + /** + * Check if it is the basic data type of json data + * + * @param type0 java class name + * @return boolean + */ + public static boolean isPrimitive(String type0) { + if (Objects.isNull(type0)) { + return true; + } + String type = type0.contains("java.lang") ? type0.substring(type0.lastIndexOf(".") + 1, type0.length()) : type0; + type = type.toLowerCase(); + switch (type) { + case "integer": + case "void": + case "int": + case "long": + case "double": + case "float": + case "short": + case "bigdecimal": + case "char": + case "string": + case "boolean": + case "byte": + case "java.sql.timestamp": + case "java.util.date": + case "java.time.localdatetime": + case "java.time.localtime": + case "localdatetime": + case "localdate": + case "java.time.localdate": + case "java.math.bigdecimal": + case "java.math.biginteger": + case "java.io.serializable": + return true; + default: + return false; + } + } + + /** + * validate java collection + * + * @param type java typeName + * @return boolean + */ + public static boolean isCollection(String type) { + switch (type) { + case "java.util.List": + case "java.util.LinkedList": + case "java.util.ArrayList": + case "java.util.Set": + case "java.util.TreeSet": + case "java.util.HashSet": + case "java.util.SortedSet": + case "java.util.Collection": + case "java.util.ArrayDeque": + case "java.util.PriorityQueue": + return true; + default: + return false; + } + } + + /** + * Check if it is an map + * + * @param type java type + * @return boolean + */ + public static boolean isMap(String type) { + switch (type) { + case "java.util.Map": + case "java.util.SortedMap": + case "java.util.TreeMap": + case "java.util.LinkedHashMap": + case "java.util.HashMap": + case "java.util.concurrent.ConcurrentHashMap": + case "java.util.concurrent.ConcurrentMap": + case "java.util.Properties": + case "java.util.Hashtable": + return true; + default: + return false; + } + } + + /** + * check array + * + * @param type type name + * @return boolean + */ + public static boolean isArray(String type) { + return type.contains("[]"); + } + + /** + * check JSR303 + * + * @param annotationSimpleName annotation name + * @return boolean + */ + public static boolean isJSR303Required(String annotationSimpleName) { + switch (annotationSimpleName) { + case "NotNull": + case "NotEmpty": + case "NotBlank": + case "Required": + return true; + default: + return false; + } + } + + + /** + * custom tag + * + * @param tagName custom field tag + * @return boolean + */ + public static boolean isRequiredTag(String tagName) { + switch (tagName) { + case "required": + return true; + default: + return false; + } + } + + /** + * ignore tag request field + * + * @param tagName custom field tag + * @return boolean + */ + public static boolean isIgnoreTag(String tagName) { + switch (tagName) { + case "ignore": + return true; + default: + return false; + } + } + + /** + * ignore param of spring mvc + * + * @param paramType param type name + * @param ignoreParams ignore param list + * @return boolean + */ + public static boolean isMvcIgnoreParams(String paramType, List ignoreParams) { + if (CollectionUtil.isNotEmpty(ignoreParams) && ignoreParams.contains(paramType)) { + return true; + } + switch (paramType) { + case "org.springframework.ui.Model": + case "org.springframework.ui.ModelMap": + case "org.springframework.web.servlet.ModelAndView": + case "org.springframework.validation.BindingResult": + case "javax.servlet.http.HttpServletRequest": + case "org.springframework.web.context.request.WebRequest": + case "javax.servlet.http.HttpSession": + case "javax.servlet.http.HttpServletResponse": + case "org.springframework.web.reactive.function.server.ServerRequest": + case "org.springframework.web.multipart.MultipartHttpServletRequest": + return true; + default: + return false; + } + } + + /** + * ignore field type name + * + * @param typeName field type name + * @return String + */ + public static boolean isIgnoreFieldTypes(String typeName) { + switch (typeName) { + case "org.slf4j.Logger": + case "org.apache.ibatis.logging.Log": + return true; + default: + return false; + } + } +} diff --git a/src/main/resources/template/yapiJson.btl b/src/main/resources/template/yapiJson.btl new file mode 100644 index 0000000..5c1cddf --- /dev/null +++ b/src/main/resources/template/yapiJson.btl @@ -0,0 +1,5 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + ${respList} +} +