├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── docs ├── html.png ├── markdown.png ├── spring-framework.png └── word.png ├── pom.xml └── src └── main ├── java └── top │ └── naccl │ ├── Cli.java │ ├── ConfigFactory.java │ ├── Main.java │ ├── MainConfig.java │ ├── engine │ ├── AbstractTemplateEngine.java │ ├── DocumentType.java │ ├── TemplateEngine.java │ ├── TemplateEngineConfig.java │ ├── TemplateEngineFactory.java │ ├── TemplateEngineType.java │ └── freemarker │ │ └── FreemarkerTemplateEngine.java │ ├── execute │ └── DocumentExecute.java │ ├── model │ ├── ClassModel.java │ ├── FieldModel.java │ ├── MethodModel.java │ ├── PackageModel.java │ ├── ParamModel.java │ └── ProjectModel.java │ ├── process │ ├── AbstractProcessor.java │ ├── ProcessConfig.java │ ├── ProjectModelProcessor.java │ └── RootDocProcessor.java │ ├── reader │ └── JavaDocReader.java │ └── util │ ├── CollectionUtils.java │ ├── FileUtils.java │ └── PropertiesUtils.java └── resources ├── app.properties ├── lib └── com │ └── sun │ └── tools │ ├── 1.8 │ ├── tools-1.8.jar │ ├── tools-1.8.jar.md5 │ ├── tools-1.8.jar.sha1 │ ├── tools-1.8.pom │ ├── tools-1.8.pom.md5 │ └── tools-1.8.pom.sha1 │ ├── maven-metadata-local.xml │ ├── maven-metadata-local.xml.md5 │ └── maven-metadata-local.xml.sha1 ├── logback.xml └── template └── freemarker ├── document_html.ftl ├── document_md.ftl └── document_word.ftl /.gitattributes: -------------------------------------------------------------------------------- 1 | *.ftl linguist-vendored -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 简介 2 | 3 | 最近写毕设论文,发现一件很奇怪的事情,要求将每个类的字段和方法签名以及对应的解释写在表格里,类似下面的图片,大胆猜测一下,这会不会是判断系统功能丰富程度的依据?如果我有几百个类,像这么一行一行去 copy,,,若是我只 copy 一部分,那会不会显得我的项目过于简单 ?🤯? 这种无用又无趣纯属浪费粮食的事情我是完全不乐意做的,按往常的经验,在 copy 的时候我会头皮发麻浑身难受然后跑去打游戏,且不说光看这种表格能看出什么所以然,但凡有一点营养我都不会写这个工具。但愿人长久,搬砖不再有。此乃文档大师必备工具! 4 | 5 | 灵感来自[screw](https://github.com/pingfangushi/screw),其实我是在论文的数据库章节用了这个工具,然后到了项目代码章节,发觉我也可以让电脑来帮我写,论文真是太坏了,竟然让电脑当苦力! 6 | 7 | ## 功能 8 | 9 | - 支持生成大型 Java 项目、多个项目、多个模块、单个类 10 | - 支持自定义模板 11 | - 支持显示或隐藏访问修饰符 12 | - 支持保留或忽略没有 JavaDoc 注释的字段、方法、类 13 | - 支持按包名、类名、字段名、方法名的前缀、后缀来忽略生成 14 | 15 | 当然前提是类中的字段或方法有 JavaDoc `/** */`,而不是单行注释`//`或多行注释`/* */`,否则将不会生成字段/方法的描述 16 | 17 | P.s. 即使是不能通过编译的 Java Class 也可以生成,只要有 `.java` 文件即可 18 | 19 | ## 文档生成支持 20 | 21 | - [x] Word 22 | - [x] HTML 23 | - [x] Markdown 24 | 25 | ## 文档截图 26 | 27 | - Word 28 | 29 | ![word](./docs/word.png) 30 | 31 | - HTML 32 | 33 | ![HTML](./docs/html.png) 34 | 35 | - Markdown 36 | 37 | ![Markdown](./docs/markdown.png) 38 | 39 | 40 | 41 | 下图是[spring-framework](https://github.com/spring-projects/spring-framework)项目代码生成的 word 文档,总大小 164 MB,耗时 70s ,讲道理很庞大的项目应该也没问题 42 | 43 | (我已经把生成的四千页贴进论文里了,老师很喜欢,孩子很开心!) 44 | 45 | ![spring-framework](./docs/spring-framework.png) 46 | 47 | ## 使用方法 48 | 49 | ### CLI 50 | 51 | 目前推荐此方式,下载 [Releases](https://github.com/Naccl/Java2Doc/releases) 中的 Java2Doc.jar,通过 CLI 调用,已测试 JDK 8、11 可用,16、17 不太行 52 | 53 | ```sh 54 | java -jar Java2Doc-x.y.z.jar -p /Users/username/YourProjectPath 55 | ``` 56 | 57 | 具体参数: 58 | 59 | ``` 60 | usage: java -jar Java2Doc-x.y.z.jar -p path1[;path2;path3;...] [-n ] [-v ] [-d ] [-o ] [-f ] [-t ] 61 | --access-modifier Display access modifier, default is true 62 | --custom-template Custom template path 63 | -d,--description The description of your project 64 | --engine-type Template engine type, can be 'freemarker' 65 | -f,--filename Document file name, default is 'Java2Doc' 66 | -h,--help This usage help 67 | --ignore-class-prefix The ignore list of class prefix, separated by ';' 68 | --ignore-class-suffix The ignore list of class suffix, separated by ';' 69 | --ignore-empty-class Ignore classes without field and method, default is false 70 | --ignore-error Ignore errors in parsing JavaDoc, default is true 71 | --ignore-field-prefix The ignore list of field prefix, separated by ';' 72 | --ignore-field-suffix The ignore list of field suffix, separated by ';' 73 | --ignore-method-prefix The ignore list of method prefix, separated by ';' 74 | --ignore-method-suffix The ignore list of method suffix, separated by ';' 75 | --ignore-nocomment-field Ignore fields without comment, default is false 76 | --ignore-nocomment-method Ignore methods without comment, default is false 77 | --ignore-pkg-prefix The ignore list of package prefix, separated by ';' 78 | --ignore-pkg-suffix The ignore list of package suffix, separated by ';' 79 | --include-private Parsing JavaDoc includes private classes and members, default is true 80 | --max-depth The maximum depth to traverse a directory starting from project path 81 | -n,--project-name The name of your project 82 | -o,--output-dir Document output directory, default is current directory 83 | -p,--project-paths The list of project paths you want to generate, separated by ';' 84 | -t,--doctype Document type, can be 'word', 'html', 'md', default is 'word' 85 | -v,--version The version of your project 86 | ``` 87 | 88 | ### Clone 89 | 90 | ```sh 91 | git clone https://github.com/Naccl/Java2Doc.git 92 | ``` 93 | 94 | 建议 JDK 8,解析 JavaDoc 依赖的 `tools.jar` 从 JDK 9+ 开始已经被移除了,虽说我已经使用在 `pom.xml` 中使用本地仓库了,但还是不确定高版本是否可用 95 | 96 | 修改 `Main.java` 中的基本配置信息 97 | 98 | ```java 99 | //待生成的项目根路径列表 100 | projectPaths.add("/Users/naccl/work/idea-project/Java2Doc"); 101 | //项目名称 102 | String projectName = "Java2Doc"; 103 | //文档版本 104 | String version = "1.0.0"; 105 | //文档描述 106 | String description = "文档大师必备工具!"; 107 | //文档输出目录 108 | String fileOutputDir = "/Users/naccl/Desktop"; 109 | //生成文档名称 110 | String fileName = "Java2Doc"; 111 | //生成文档类型 DocumentType.WORD、DocumentType.HTML、DocumentType.MARKDOWN 112 | DocumentType documentType = DocumentType.WORD; 113 | ``` 114 | 115 | 然后直接 Run 它! 116 | 117 | 如果你配置过 Maven 镜像仓库,且 Maven 的配置文件(通常是`~/.m2/settings.xml` )中对应镜像的 `mirrorOf` 是 `*`,那么 `pom.xml` 中配置的 repository 将不起作用,需要改为 118 | 119 | ```xml 120 | external:* 121 | ``` 122 | 123 | 只让外部仓库的走镜像,本地的继续走本地 124 | 125 | ### Maven 126 | 127 | WIP 128 | 129 | ## 已知问题 130 | 131 | 由于 Java 类中的字段注释、方法注释是通过调用 `com.sun.tools` 解析 JavaDoc 获取的,JavaDoc 有个参数 `-classpath` 可以指定加载要解析的 Java 类中 import 的包。但往往项目需要的依赖相当多,并且通常是 Maven、Gradle 方式来引入依赖,难以全部作为 `-classpath` 的值提供给 JavaDoc 解析器,所以会导致一些自定义类的泛型解析结果为 `` ,本项目中的做法是将这些 `` 替换成 `T` 来显示,尚不知是否有更好的办法。 132 | 133 | ## 参与贡献 134 | 135 | - 文档格式 136 | 137 | 除了 Word、HTML、Markdown,或许还有其它可以实现的格式 138 | 139 | - 模板样式 140 | 141 | 每个人可能有不同的样式需求,一般都需要编写专门的模板,大伙们可以分享自己的模板 142 | 143 | - 模板引擎 144 | 145 | 其它的模板引擎实现,如 thymeleaf、velocity 146 | 147 | 欢迎 PR! 148 | 149 | ## License 150 | 151 | [Apache-2.0 License](https://github.com/Naccl/Java2Doc/blob/master/LICENSE) 152 | 153 | ## Thanks 154 | 155 | 再次感谢 [screw](https://github.com/pingfangushi/screw),项目实现过程中参考了 screw 的设计思路 156 | 157 | -------------------------------------------------------------------------------- /docs/html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naccl/Java2Doc/a928088c86aab9459f989b0a50d0de6270e547fd/docs/html.png -------------------------------------------------------------------------------- /docs/markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naccl/Java2Doc/a928088c86aab9459f989b0a50d0de6270e547fd/docs/markdown.png -------------------------------------------------------------------------------- /docs/spring-framework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naccl/Java2Doc/a928088c86aab9459f989b0a50d0de6270e547fd/docs/spring-framework.png -------------------------------------------------------------------------------- /docs/word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naccl/Java2Doc/a928088c86aab9459f989b0a50d0de6270e547fd/docs/word.png -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | top.naccl 8 | Java2Doc 9 | ${java2doc.version} 10 | 11 | 12 | 1.8 13 | 8 14 | 8 15 | UTF-8 16 | 17 | 1.9 18 | 2.3.30 19 | 1.18.22 20 | 1.7.36 21 | 1.2.10 22 | 1.5.0 23 | 24 | 25 | 26 | 27 | java2doc-local 28 | file://${project.basedir}/src/main/resources/lib 29 | 30 | 31 | 32 | 33 | 34 | 35 | com.sun 36 | tools 37 | 1.8 38 | 39 | 40 | 41 | org.apache.commons 42 | commons-text 43 | ${commons-text.version} 44 | 45 | 46 | 47 | org.freemarker 48 | freemarker 49 | ${freemarker.version} 50 | 51 | 52 | 53 | org.slf4j 54 | slf4j-api 55 | ${slf4j-api.version} 56 | 57 | 58 | 59 | ch.qos.logback 60 | logback-classic 61 | ${logback-classic.version} 62 | 63 | 64 | 65 | commons-cli 66 | commons-cli 67 | ${commons-cli.version} 68 | 69 | 70 | 71 | org.projectlombok 72 | lombok 73 | ${lombok.version} 74 | provided 75 | 76 | 77 | 78 | 79 | 80 | 81 | org.codehaus.mojo 82 | properties-maven-plugin 83 | 1.0.0 84 | 85 | 86 | initialize 87 | 88 | read-project-properties 89 | 90 | 91 | 92 | ${project.basedir}/src/main/resources/app.properties 93 | 94 | 95 | 96 | 97 | 98 | 99 | org.apache.maven.plugins 100 | maven-assembly-plugin 101 | 102 | 103 | package 104 | 105 | single 106 | 107 | 108 | 109 | 110 | 111 | 112 | top.naccl.Cli 113 | 114 | 115 | 116 | jar-with-dependencies 117 | 118 | false 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/Cli.java: -------------------------------------------------------------------------------- 1 | package top.naccl; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.apache.commons.cli.CommandLine; 5 | import org.apache.commons.cli.DefaultParser; 6 | import org.apache.commons.cli.HelpFormatter; 7 | import org.apache.commons.cli.Option; 8 | import org.apache.commons.cli.Options; 9 | import org.apache.commons.cli.ParseException; 10 | import top.naccl.engine.DocumentType; 11 | import top.naccl.engine.TemplateEngineType; 12 | import top.naccl.execute.DocumentExecute; 13 | import top.naccl.util.PropertiesUtils; 14 | 15 | import java.util.Arrays; 16 | 17 | /** 18 | * CLI执行类 19 | * 20 | * @author: Naccl 21 | * @date: 2022-04-21 22 | */ 23 | @Slf4j 24 | public class Cli { 25 | /** 26 | * 命令行配置 27 | */ 28 | private Options options; 29 | /** 30 | * 用法提示 31 | */ 32 | private static final String USAGE = "java -jar Java2Doc-" + PropertiesUtils.getVersion() + ".jar -p path1[;path2;path3;...] [-n ] [-v ] [-d ] [-o ] [-f ] [-t ]"; 33 | /** 34 | * 命令行参数列表 35 | */ 36 | private static final String OPTION_HELP = "help"; 37 | private static final String OPTION_PROJECT_PATHS = "project-paths"; 38 | private static final String OPTION_MAX_DEPTH = "max-depth"; 39 | private static final String OPTION_PROJECT_NAME = "project-name"; 40 | private static final String OPTION_VERSION = "version"; 41 | private static final String OPTION_DESCRIPTION = "description"; 42 | private static final String OPTION_INCLUDE_PRIVATE = "include-private"; 43 | private static final String OPTION_IGNORE_ERROR = "ignore-error"; 44 | private static final String OPTION_OUTPUT_DIR = "output-dir"; 45 | private static final String OPTION_FILENAME = "filename"; 46 | private static final String OPTION_DOCTYPE = "doctype"; 47 | private static final String OPTION_ENGINE_TYPE = "engine-type"; 48 | private static final String OPTION_CUSTOM_TEMPLATE = "custom-template"; 49 | private static final String OPTION_ACCESS_MODIFIER = "access-modifier"; 50 | private static final String OPTION_IGNORE_EMPTY_CLASS = "ignore-empty-class"; 51 | private static final String OPTION_IGNORE_NOCOMMENT_FIELD = "ignore-nocomment-field"; 52 | private static final String OPTION_IGNORE_NOCOMMENT_METHOD = "ignore-nocomment-method"; 53 | private static final String OPTION_IGNORE_PKG_PREFIX = "ignore-pkg-prefix"; 54 | private static final String OPTION_IGNORE_PKG_SUFFIX = "ignore-pkg-suffix"; 55 | private static final String OPTION_IGNORE_CLASS_PREFIX = "ignore-class-prefix"; 56 | private static final String OPTION_IGNORE_CLASS_SUFFIX = "ignore-class-suffix"; 57 | private static final String OPTION_IGNORE_FIELD_PREFIX = "ignore-field-prefix"; 58 | private static final String OPTION_IGNORE_FIELD_SUFFIX = "ignore-field-suffix"; 59 | private static final String OPTION_IGNORE_METHOD_PREFIX = "ignore-method-prefix"; 60 | private static final String OPTION_IGNORE_METHOD_SUFFIX = "ignore-method-suffix"; 61 | 62 | 63 | /** 64 | * CLI入口 65 | * 66 | * @param args 命令行参数 67 | */ 68 | public static void main(String[] args) { 69 | Cli cli = new Cli(); 70 | MainConfig mainConfig = null; 71 | try { 72 | CommandLine cmd = cli.initCli(args); 73 | mainConfig = cli.generateConfig(cmd); 74 | } catch (Exception e) { 75 | System.out.println(e.getMessage()); 76 | cli.printHelp(); 77 | System.exit(22); 78 | } 79 | 80 | log.debug("MainConfig: {}", mainConfig); 81 | if (mainConfig == null) { 82 | log.error("An error occurred while generating the configuration"); 83 | return; 84 | } 85 | //执行文档生成 86 | new DocumentExecute(mainConfig).execute(); 87 | } 88 | 89 | /** 90 | * 初始化命令行接口 91 | * 92 | * @param args 命令行参数 93 | */ 94 | private CommandLine initCli(String[] args) throws ParseException { 95 | this.options = initOptions(); 96 | return new DefaultParser().parse(options, args); 97 | } 98 | 99 | /** 100 | * 打印帮助信息 101 | */ 102 | private void printHelp() { 103 | new HelpFormatter().printHelp(120, USAGE, null, options, null); 104 | } 105 | 106 | /** 107 | * 初始化命令行选项 108 | * 109 | * @return 命令行选项配置 110 | */ 111 | @SuppressWarnings("unckecked all") 112 | private Options initOptions() { 113 | Option help = Option.builder("h") 114 | .longOpt(OPTION_HELP) 115 | .desc("This usage help") 116 | .required(false) 117 | .hasArg(false) 118 | .build(); 119 | Option projectPaths = Option.builder("p") 120 | .longOpt(OPTION_PROJECT_PATHS) 121 | .argName("pathlist") 122 | .desc("The list of project paths you want to generate, separated by ';'") 123 | .required(true) 124 | .hasArgs() 125 | .optionalArg(false) 126 | .valueSeparator(';') 127 | .build(); 128 | Option maxDepth = Option.builder() 129 | .longOpt(OPTION_MAX_DEPTH) 130 | .argName("number") 131 | .desc("The maximum depth to traverse a directory starting from project path") 132 | .required(false) 133 | .hasArg(true) 134 | .optionalArg(false) 135 | .type(Integer.class) 136 | .build(); 137 | Option projectName = Option.builder("n") 138 | .longOpt(OPTION_PROJECT_NAME) 139 | .argName("name") 140 | .desc("The name of your project") 141 | .required(false) 142 | .hasArg(true) 143 | .optionalArg(false) 144 | .build(); 145 | Option version = Option.builder("v") 146 | .longOpt(OPTION_VERSION) 147 | .argName("version") 148 | .desc("The version of your project") 149 | .required(false) 150 | .hasArg(true) 151 | .optionalArg(false) 152 | .build(); 153 | Option description = Option.builder("d") 154 | .longOpt(OPTION_DESCRIPTION) 155 | .argName("desc") 156 | .desc("The description of your project") 157 | .required(false) 158 | .hasArg(true) 159 | .optionalArg(false) 160 | .build(); 161 | Option includePrivate = Option.builder() 162 | .longOpt(OPTION_INCLUDE_PRIVATE) 163 | .argName("true/false") 164 | .desc("Parsing JavaDoc includes private classes and members, default is true") 165 | .required(false) 166 | .hasArg(true) 167 | .optionalArg(false) 168 | .type(Boolean.class) 169 | .build(); 170 | Option ignoreJavaDocError = Option.builder() 171 | .longOpt(OPTION_IGNORE_ERROR) 172 | .argName("true/false") 173 | .desc("Ignore errors in parsing JavaDoc, default is true") 174 | .required(false) 175 | .hasArg(true) 176 | .optionalArg(false) 177 | .type(Boolean.class) 178 | .build(); 179 | Option fileOutputDir = Option.builder("o") 180 | .longOpt(OPTION_OUTPUT_DIR) 181 | .argName("path") 182 | .desc("Document output directory, default is current directory") 183 | .required(false) 184 | .hasArg(true) 185 | .optionalArg(false) 186 | .build(); 187 | Option fileName = Option.builder("f") 188 | .longOpt(OPTION_FILENAME) 189 | .argName("name") 190 | .desc("Document file name, default is 'Java2Doc'") 191 | .required(false) 192 | .hasArg(true) 193 | .optionalArg(false) 194 | .build(); 195 | Option documentType = Option.builder("t") 196 | .longOpt(OPTION_DOCTYPE) 197 | .argName("type") 198 | .desc("Document type, can be 'word', 'html', 'md', default is 'word'") 199 | .required(false) 200 | .hasArg(true) 201 | .optionalArg(false) 202 | .build(); 203 | Option templateEngineType = Option.builder() 204 | .longOpt(OPTION_ENGINE_TYPE) 205 | .argName("type") 206 | .desc("Template engine type, can be 'freemarker'") 207 | .required(false) 208 | .hasArg(true) 209 | .optionalArg(false) 210 | .build(); 211 | Option customTemplatePath = Option.builder() 212 | .longOpt(OPTION_CUSTOM_TEMPLATE) 213 | .argName("path") 214 | .desc("Custom template path") 215 | .required(false) 216 | .hasArg(true) 217 | .optionalArg(false) 218 | .build(); 219 | Option displayAccessModifier = Option.builder() 220 | .longOpt(OPTION_ACCESS_MODIFIER) 221 | .argName("true/false") 222 | .desc("Display access modifier, default is true") 223 | .required(false) 224 | .hasArg(true) 225 | .optionalArg(false) 226 | .type(Boolean.class) 227 | .build(); 228 | Option ignoreClassWithoutFieldAndMethod = Option.builder() 229 | .longOpt(OPTION_IGNORE_EMPTY_CLASS) 230 | .argName("true/false") 231 | .desc("Ignore classes without field and method, default is false") 232 | .required(false) 233 | .hasArg(true) 234 | .optionalArg(false) 235 | .type(Boolean.class) 236 | .build(); 237 | Option ignoreFieldWithoutComment = Option.builder() 238 | .longOpt(OPTION_IGNORE_NOCOMMENT_FIELD) 239 | .argName("true/false") 240 | .desc("Ignore fields without comment, default is false") 241 | .required(false) 242 | .hasArg(true) 243 | .optionalArg(false) 244 | .type(Boolean.class) 245 | .build(); 246 | Option ignoreMethodWithoutComment = Option.builder() 247 | .longOpt(OPTION_IGNORE_NOCOMMENT_METHOD) 248 | .argName("true/false") 249 | .desc("Ignore methods without comment, default is false") 250 | .required(false) 251 | .hasArg(true) 252 | .optionalArg(false) 253 | .type(Boolean.class) 254 | .build(); 255 | Option ignorePackagePrefix = Option.builder() 256 | .longOpt(OPTION_IGNORE_PKG_PREFIX) 257 | .argName("prefixlist") 258 | .desc("The ignore list of package prefix, separated by ';'") 259 | .required(false) 260 | .hasArgs() 261 | .optionalArg(false) 262 | .valueSeparator(';') 263 | .build(); 264 | Option ignorePackageSuffix = Option.builder() 265 | .longOpt(OPTION_IGNORE_PKG_SUFFIX) 266 | .argName("suffixlist") 267 | .desc("The ignore list of package suffix, separated by ';'") 268 | .required(false) 269 | .hasArgs() 270 | .optionalArg(false) 271 | .valueSeparator(';') 272 | .build(); 273 | Option ignoreClassPrefix = Option.builder() 274 | .longOpt(OPTION_IGNORE_CLASS_PREFIX) 275 | .argName("prefixlist") 276 | .desc("The ignore list of class prefix, separated by ';'") 277 | .required(false) 278 | .hasArgs() 279 | .optionalArg(false) 280 | .valueSeparator(';') 281 | .build(); 282 | Option ignoreClassSuffix = Option.builder() 283 | .longOpt(OPTION_IGNORE_CLASS_SUFFIX) 284 | .argName("suffixlist") 285 | .desc("The ignore list of class suffix, separated by ';'") 286 | .required(false) 287 | .hasArgs() 288 | .optionalArg(false) 289 | .valueSeparator(';') 290 | .build(); 291 | Option ignoreFieldPrefix = Option.builder() 292 | .longOpt(OPTION_IGNORE_FIELD_PREFIX) 293 | .argName("prefixlist") 294 | .desc("The ignore list of field prefix, separated by ';'") 295 | .required(false) 296 | .hasArgs() 297 | .optionalArg(false) 298 | .valueSeparator(';') 299 | .build(); 300 | Option ignoreFieldSuffix = Option.builder() 301 | .longOpt(OPTION_IGNORE_FIELD_SUFFIX) 302 | .argName("suffixlist") 303 | .desc("The ignore list of field suffix, separated by ';'") 304 | .required(false) 305 | .hasArgs() 306 | .optionalArg(false) 307 | .valueSeparator(';') 308 | .build(); 309 | Option ignoreMethodPrefix = Option.builder() 310 | .longOpt(OPTION_IGNORE_METHOD_PREFIX) 311 | .argName("prefixlist") 312 | .desc("The ignore list of method prefix, separated by ';'") 313 | .required(false) 314 | .hasArgs() 315 | .optionalArg(false) 316 | .valueSeparator(';') 317 | .build(); 318 | Option ignoreMethodSuffix = Option.builder() 319 | .longOpt(OPTION_IGNORE_METHOD_SUFFIX) 320 | .argName("suffixlist") 321 | .desc("The ignore list of method suffix, separated by ';'") 322 | .required(false) 323 | .hasArgs() 324 | .optionalArg(false) 325 | .valueSeparator(';') 326 | .build(); 327 | 328 | return new Options() 329 | .addOption(help) 330 | .addOption(projectPaths) 331 | .addOption(maxDepth) 332 | .addOption(projectName) 333 | .addOption(version) 334 | .addOption(description) 335 | .addOption(includePrivate) 336 | .addOption(ignoreJavaDocError) 337 | .addOption(fileOutputDir) 338 | .addOption(fileName) 339 | .addOption(documentType) 340 | .addOption(templateEngineType) 341 | .addOption(customTemplatePath) 342 | .addOption(displayAccessModifier) 343 | .addOption(ignoreClassWithoutFieldAndMethod) 344 | .addOption(ignoreFieldWithoutComment) 345 | .addOption(ignoreMethodWithoutComment) 346 | .addOption(ignorePackagePrefix) 347 | .addOption(ignorePackageSuffix) 348 | .addOption(ignoreClassPrefix) 349 | .addOption(ignoreClassSuffix) 350 | .addOption(ignoreFieldPrefix) 351 | .addOption(ignoreFieldSuffix) 352 | .addOption(ignoreMethodPrefix) 353 | .addOption(ignoreMethodSuffix) 354 | ; 355 | } 356 | 357 | /** 358 | * 处理命令行参数,并生成配置 359 | * 360 | * @param cmd 命令行参数解析结果 361 | * @return 配置 362 | */ 363 | private MainConfig generateConfig(CommandLine cmd) { 364 | if (cmd.hasOption(OPTION_HELP)) { 365 | printHelp(); 366 | System.exit(0); 367 | } 368 | 369 | // 项目路径是必须的参数 370 | if (!cmd.hasOption(OPTION_PROJECT_PATHS)) { 371 | System.out.println("Missing required option: p"); 372 | printHelp(); 373 | System.exit(22); 374 | } 375 | String[] projectPaths = cmd.getOptionValues(OPTION_PROJECT_PATHS); 376 | MainConfig config = ConfigFactory.defaultMainConfig(Arrays.asList(projectPaths)); 377 | 378 | if (cmd.hasOption(OPTION_MAX_DEPTH)) { 379 | int maxDepth = Integer.parseInt(cmd.getOptionValue(OPTION_MAX_DEPTH)); 380 | config.setMaxDepth(maxDepth); 381 | } 382 | if (cmd.hasOption(OPTION_PROJECT_NAME)) { 383 | String projectName = cmd.getOptionValue(OPTION_PROJECT_NAME); 384 | config.setProjectName(projectName); 385 | } 386 | if (cmd.hasOption(OPTION_VERSION)) { 387 | String version = cmd.getOptionValue(OPTION_VERSION); 388 | config.setVersion(version); 389 | } 390 | if (cmd.hasOption(OPTION_DESCRIPTION)) { 391 | String description = cmd.getOptionValue(OPTION_DESCRIPTION); 392 | config.setDescription(description); 393 | } 394 | if (cmd.hasOption(OPTION_INCLUDE_PRIVATE)) { 395 | boolean includePrivate = Boolean.parseBoolean(cmd.getOptionValue(OPTION_INCLUDE_PRIVATE)); 396 | config.setIncludePrivate(includePrivate); 397 | } 398 | if (cmd.hasOption(OPTION_IGNORE_ERROR)) { 399 | boolean ignoreJavaDocError = Boolean.parseBoolean(cmd.getOptionValue(OPTION_IGNORE_ERROR)); 400 | config.setIgnoreJavaDocError(ignoreJavaDocError); 401 | } 402 | if (cmd.hasOption(OPTION_OUTPUT_DIR)) { 403 | String fileOutputDir = cmd.getOptionValue(OPTION_OUTPUT_DIR); 404 | config.getTemplateEngineConfig().setFileOutputDir(fileOutputDir); 405 | } 406 | if (cmd.hasOption(OPTION_FILENAME)) { 407 | String fileName = cmd.getOptionValue(OPTION_FILENAME); 408 | config.getTemplateEngineConfig().setFileName(fileName); 409 | } 410 | if (cmd.hasOption(OPTION_DOCTYPE)) { 411 | String doctype = cmd.getOptionValue(OPTION_DOCTYPE); 412 | DocumentType documentType = DocumentType.valueOf(doctype.toUpperCase()); 413 | config.getTemplateEngineConfig().setDocumentType(documentType); 414 | } 415 | if (cmd.hasOption(OPTION_ENGINE_TYPE)) { 416 | String templateEngineType = cmd.getOptionValue(OPTION_ENGINE_TYPE); 417 | TemplateEngineType engineType = TemplateEngineType.valueOf(templateEngineType.toUpperCase()); 418 | config.getTemplateEngineConfig().setTemplateEngineType(engineType); 419 | } 420 | if (cmd.hasOption(OPTION_CUSTOM_TEMPLATE)) { 421 | String customTemplatePath = cmd.getOptionValue(OPTION_CUSTOM_TEMPLATE); 422 | config.getTemplateEngineConfig().setCustomTemplatePath(customTemplatePath); 423 | } 424 | if (cmd.hasOption(OPTION_ACCESS_MODIFIER)) { 425 | boolean displayAccessModifier = Boolean.parseBoolean(cmd.getOptionValue(OPTION_ACCESS_MODIFIER)); 426 | config.getProcessConfig().setDisplayAccessModifier(displayAccessModifier); 427 | } 428 | if (cmd.hasOption(OPTION_IGNORE_EMPTY_CLASS)) { 429 | boolean ignoreEmptyClass = Boolean.parseBoolean(cmd.getOptionValue(OPTION_IGNORE_EMPTY_CLASS)); 430 | config.getProcessConfig().setIgnoreClassWithoutFieldAndMethod(ignoreEmptyClass); 431 | } 432 | if (cmd.hasOption(OPTION_IGNORE_NOCOMMENT_FIELD)) { 433 | boolean ignoreNoCommentField = Boolean.parseBoolean(cmd.getOptionValue(OPTION_IGNORE_NOCOMMENT_FIELD)); 434 | config.getProcessConfig().setIgnoreFieldWithoutComment(ignoreNoCommentField); 435 | } 436 | if (cmd.hasOption(OPTION_IGNORE_NOCOMMENT_METHOD)) { 437 | boolean ignoreNoCommentMethod = Boolean.parseBoolean(cmd.getOptionValue(OPTION_IGNORE_NOCOMMENT_METHOD)); 438 | config.getProcessConfig().setIgnoreMethodWithoutComment(ignoreNoCommentMethod); 439 | } 440 | if (cmd.hasOption(OPTION_IGNORE_PKG_PREFIX)) { 441 | String[] ignorePkgPrefix = cmd.getOptionValues(OPTION_IGNORE_PKG_PREFIX); 442 | config.getProcessConfig().setIgnorePackagePrefix(Arrays.asList(ignorePkgPrefix)); 443 | } 444 | if (cmd.hasOption(OPTION_IGNORE_PKG_SUFFIX)) { 445 | String[] ignorePkgSuffix = cmd.getOptionValues(OPTION_IGNORE_PKG_SUFFIX); 446 | config.getProcessConfig().setIgnorePackageSuffix(Arrays.asList(ignorePkgSuffix)); 447 | } 448 | if (cmd.hasOption(OPTION_IGNORE_CLASS_PREFIX)) { 449 | String[] ignoreClassPrefix = cmd.getOptionValues(OPTION_IGNORE_CLASS_PREFIX); 450 | config.getProcessConfig().setIgnoreClassPrefix(Arrays.asList(ignoreClassPrefix)); 451 | } 452 | if (cmd.hasOption(OPTION_IGNORE_CLASS_SUFFIX)) { 453 | String[] ignoreClassSuffix = cmd.getOptionValues(OPTION_IGNORE_CLASS_SUFFIX); 454 | config.getProcessConfig().setIgnoreClassSuffix(Arrays.asList(ignoreClassSuffix)); 455 | } 456 | if (cmd.hasOption(OPTION_IGNORE_FIELD_PREFIX)) { 457 | String[] ignoreFieldPrefix = cmd.getOptionValues(OPTION_IGNORE_FIELD_PREFIX); 458 | config.getProcessConfig().setIgnoreFieldPrefix(Arrays.asList(ignoreFieldPrefix)); 459 | } 460 | if (cmd.hasOption(OPTION_IGNORE_FIELD_SUFFIX)) { 461 | String[] ignoreFieldSuffix = cmd.getOptionValues(OPTION_IGNORE_FIELD_SUFFIX); 462 | config.getProcessConfig().setIgnoreFieldSuffix(Arrays.asList(ignoreFieldSuffix)); 463 | } 464 | if (cmd.hasOption(OPTION_IGNORE_METHOD_PREFIX)) { 465 | String[] ignoreMethodPrefix = cmd.getOptionValues(OPTION_IGNORE_METHOD_PREFIX); 466 | config.getProcessConfig().setIgnoreMethodPrefix(Arrays.asList(ignoreMethodPrefix)); 467 | } 468 | if (cmd.hasOption(OPTION_IGNORE_METHOD_SUFFIX)) { 469 | String[] ignoreMethodSuffix = cmd.getOptionValues(OPTION_IGNORE_METHOD_SUFFIX); 470 | config.getProcessConfig().setIgnoreMethodSuffix(Arrays.asList(ignoreMethodSuffix)); 471 | } 472 | return config; 473 | } 474 | } 475 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/ConfigFactory.java: -------------------------------------------------------------------------------- 1 | package top.naccl; 2 | 3 | import top.naccl.engine.DocumentType; 4 | import top.naccl.engine.TemplateEngineConfig; 5 | import top.naccl.engine.TemplateEngineType; 6 | import top.naccl.process.ProcessConfig; 7 | import top.naccl.util.FileUtils; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * 配置工厂 13 | * 14 | * @author: Naccl 15 | * @date: 2022-04-21 16 | */ 17 | public class ConfigFactory { 18 | /** 19 | * 默认文档处理器配置 20 | * 21 | * @return 文档处理器配置 22 | */ 23 | public static ProcessConfig defaultProcessConfig() { 24 | return ProcessConfig.builder() 25 | //是否显示访问修饰符(字段、方法) 26 | .displayAccessModifier(true) 27 | //忽略没有字段和方法的类 28 | .ignoreClassWithoutFieldAndMethod(false) 29 | //忽略没有JavaDoc注释的字段 30 | .ignoreFieldWithoutComment(false) 31 | //忽略没有JavaDoc注释的方法 32 | .ignoreMethodWithoutComment(false) 33 | .build(); 34 | } 35 | 36 | /** 37 | * 默认模板引擎配置 38 | * 39 | * @return 模板引擎配置 40 | */ 41 | public static TemplateEngineConfig defaultTemplateEngineConfig() { 42 | return TemplateEngineConfig.builder() 43 | //文档输出目录 44 | .fileOutputDir(FileUtils.getCurrentPath()) 45 | //生成文档名称 46 | .fileName("Java2Doc") 47 | //生成文档类型 48 | .documentType(DocumentType.WORD) 49 | //模板引擎类型 50 | .templateEngineType(TemplateEngineType.FREEMARKER) 51 | .build(); 52 | } 53 | 54 | /** 55 | * 默认主配置 56 | * 57 | * @return 主配置 58 | */ 59 | public static MainConfig defaultMainConfig(List projectPaths) { 60 | return MainConfig.builder() 61 | .projectPaths(projectPaths) 62 | //遍历目录的最大深度(默认Integer.MAX_VALUE) 63 | .maxDepth(Integer.MAX_VALUE) 64 | //项目名称 65 | .projectName("Java2Doc") 66 | //文档版本 67 | .version("1.0.0") 68 | //文档描述 69 | .description("文档大师必备工具!") 70 | //解析private的类和成员(默认true) 71 | .includePrivate(true) 72 | //忽略解析JavaDoc时的错误(默认true) 73 | .ignoreJavaDocError(true) 74 | //模板引擎配置 75 | .templateEngineConfig(defaultTemplateEngineConfig()) 76 | //文档处理器配置 77 | .processConfig(defaultProcessConfig()) 78 | .build(); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/Main.java: -------------------------------------------------------------------------------- 1 | package top.naccl; 2 | 3 | import top.naccl.engine.DocumentType; 4 | import top.naccl.engine.TemplateEngineConfig; 5 | import top.naccl.engine.TemplateEngineType; 6 | import top.naccl.execute.DocumentExecute; 7 | import top.naccl.process.ProcessConfig; 8 | 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | /** 13 | * @author: Naccl 14 | * @date: 2022-04-18 15 | */ 16 | public class Main { 17 | 18 | public static void main(String[] args) { 19 | new DocumentExecute(miniConfig()).execute(); 20 | } 21 | 22 | /** 23 | * 基础配置 24 | * 25 | * @return MainConfig 26 | */ 27 | @SuppressWarnings("unchecked all") 28 | private static MainConfig miniConfig() { 29 | List projectPaths = new ArrayList<>(); 30 | 31 | //==============================需要修改的基础配置============================== 32 | //待生成的项目根路径列表 33 | projectPaths.add("/Users/naccl/work/idea-project/Java2Doc"); 34 | //项目名称 35 | String projectName = "Java2Doc"; 36 | //文档版本 37 | String version = "1.0.0"; 38 | //文档描述 39 | String description = "文档大师必备工具!"; 40 | //文档输出目录 41 | String fileOutputDir = "/Users/naccl/Desktop"; 42 | //生成文档名称 43 | String fileName = "Java2Doc"; 44 | //生成文档类型 DocumentType.WORD、DocumentType.HTML、DocumentType.MARKDOWN 45 | DocumentType documentType = DocumentType.WORD; 46 | //=========================================================================== 47 | 48 | 49 | ProcessConfig processConfig = ProcessConfig.builder() 50 | //是否显示访问修饰符(字段、方法) 51 | .displayAccessModifier(true) 52 | //忽略没有字段和方法的类 53 | .ignoreClassWithoutFieldAndMethod(false) 54 | //忽略没有JavaDoc注释的字段 55 | .ignoreFieldWithoutComment(false) 56 | //忽略没有JavaDoc注释的方法 57 | .ignoreMethodWithoutComment(false) 58 | .build(); 59 | 60 | TemplateEngineConfig templateEngineConfig = TemplateEngineConfig.builder() 61 | //文档输出目录 62 | .fileOutputDir(fileOutputDir) 63 | //生成文档名称 64 | .fileName(fileName) 65 | //生成文档类型 66 | .documentType(documentType) 67 | //模板引擎类型 68 | .templateEngineType(TemplateEngineType.FREEMARKER) 69 | .build(); 70 | 71 | MainConfig config = MainConfig.builder() 72 | //待生成的项目根路径列表 73 | .projectPaths(projectPaths) 74 | //遍历目录的最大深度(默认Integer.MAX_VALUE) 75 | .maxDepth(Integer.MAX_VALUE) 76 | //项目名称 77 | .projectName(projectName) 78 | //文档版本 79 | .version(version) 80 | //文档描述 81 | .description(description) 82 | //解析private的类和成员(默认true) 83 | .includePrivate(true) 84 | //忽略解析JavaDoc时的错误(默认true) 85 | .ignoreJavaDocError(true) 86 | //模板引擎配置 87 | .templateEngineConfig(templateEngineConfig) 88 | //文档处理器配置 89 | .processConfig(processConfig) 90 | .build(); 91 | return config; 92 | } 93 | 94 | /** 95 | * 完整配置 96 | * 97 | * @return MainConfig 98 | */ 99 | @SuppressWarnings("unchecked all") 100 | private static MainConfig allConfig() { 101 | //忽略包名前缀 102 | List ignorePackagePrefix = new ArrayList<>(); 103 | ignorePackagePrefix.add("top."); 104 | //忽略包名后缀 105 | List ignorePackageSuffix = new ArrayList<>(); 106 | ignorePackageSuffix.add(".naccl"); 107 | //忽略类名前缀 108 | List ignoreClassPrefix = new ArrayList<>(); 109 | ignoreClassPrefix.add("Test"); 110 | //忽略类名后缀 111 | List ignoreClassSuffix = new ArrayList<>(); 112 | ignoreClassSuffix.add("Controller"); 113 | //忽略字段名前缀 114 | List ignoreFieldPrefix = new ArrayList<>(); 115 | ignoreFieldPrefix.add("is"); 116 | //忽略字段名后缀 117 | List ignoreFieldSuffix = new ArrayList<>(); 118 | ignoreFieldSuffix.add("Suffix"); 119 | //忽略方法名前缀 120 | List ignoreMethodPrefix = new ArrayList<>(); 121 | ignoreMethodPrefix.add("get"); 122 | //忽略方法名后缀 123 | List ignoreMethodSuffix = new ArrayList<>(); 124 | ignoreMethodSuffix.add("Suffix"); 125 | 126 | ProcessConfig processConfig = ProcessConfig.builder() 127 | //是否显示访问修饰符(字段、方法) 128 | .displayAccessModifier(true) 129 | //忽略没有字段和方法的类 130 | .ignoreClassWithoutFieldAndMethod(false) 131 | //忽略没有JavaDoc注释的字段 132 | .ignoreFieldWithoutComment(false) 133 | //忽略没有JavaDoc注释的方法 134 | .ignoreMethodWithoutComment(false) 135 | //忽略包名前缀 136 | .ignorePackagePrefix(ignorePackagePrefix) 137 | //忽略包名后缀 138 | .ignorePackageSuffix(ignorePackageSuffix) 139 | //忽略类名前缀 140 | .ignoreClassPrefix(ignoreClassPrefix) 141 | //忽略类名后缀 142 | .ignoreClassSuffix(ignoreClassSuffix) 143 | //忽略字段名前缀 144 | .ignoreFieldPrefix(ignoreFieldPrefix) 145 | //忽略字段名后缀 146 | .ignoreFieldSuffix(ignoreFieldSuffix) 147 | //忽略方法名前缀 148 | .ignoreMethodPrefix(ignoreMethodPrefix) 149 | //忽略方法名后缀 150 | .ignoreMethodSuffix(ignoreMethodSuffix) 151 | .build(); 152 | 153 | TemplateEngineConfig templateEngineConfig = TemplateEngineConfig.builder() 154 | //文档输出目录 155 | .fileOutputDir("/Users/naccl/Desktop") 156 | //生成文档名称 157 | .fileName("Java2Doc") 158 | //生成文档类型 159 | .documentType(DocumentType.WORD) 160 | //模板引擎类型 161 | .templateEngineType(TemplateEngineType.FREEMARKER) 162 | //自定义模板路径(需要自己编写模板,否则使用默认即可) 163 | .customTemplatePath("/Users/naccl/Desktop/test_document_word.ftl") 164 | .build(); 165 | 166 | //待生成的项目根路径列表 167 | //可以添加多个项目或模块到List中,将会在同一个文档中一起生成 168 | //如果只需要生成单个模块或目录下的Java文件,则路径精确到对应目录即可,精确到单个Java文件亦可 169 | List projectPaths = new ArrayList<>(); 170 | projectPaths.add("/Users/naccl/work/idea-project/Java2Doc"); 171 | //projectPaths.add("/Users/naccl/Desktop/spring-framework"); 172 | //projectPaths.add("/Users/naccl/Desktop/spring-boot"); 173 | 174 | MainConfig config = MainConfig.builder() 175 | //待生成的项目根路径列表 176 | .projectPaths(projectPaths) 177 | //遍历目录的最大深度(默认Integer.MAX_VALUE) 178 | .maxDepth(Integer.MAX_VALUE) 179 | //项目名称 180 | .projectName("Java2Doc") 181 | //文档版本 182 | .version("1.0.0") 183 | //文档描述 184 | .description("文档大师必备工具!") 185 | //解析private的类和成员(默认true) 186 | .includePrivate(true) 187 | //忽略解析JavaDoc时的错误(默认true) 188 | .ignoreJavaDocError(true) 189 | //模板引擎配置 190 | .templateEngineConfig(templateEngineConfig) 191 | //文档处理器配置 192 | .processConfig(processConfig) 193 | .build(); 194 | return config; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/MainConfig.java: -------------------------------------------------------------------------------- 1 | package top.naccl; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | import top.naccl.engine.TemplateEngineConfig; 8 | import top.naccl.process.ProcessConfig; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 主配置 14 | * 15 | * @author: Naccl 16 | * @date: 2022-04-19 17 | */ 18 | @Data 19 | @Builder 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | public class MainConfig { 23 | /** 24 | * 待生成的项目根路径列表 25 | */ 26 | private List projectPaths; 27 | /** 28 | * 遍历目录的最大深度(默认Integer.MAX_VALUE) 29 | */ 30 | private int maxDepth; 31 | /** 32 | * 项目名称 33 | */ 34 | private String projectName; 35 | /** 36 | * 文档版本 37 | */ 38 | private String version; 39 | /** 40 | * 文档描述 41 | */ 42 | private String description; 43 | /** 44 | * 解析private的类和成员(默认true) 45 | */ 46 | private boolean includePrivate; 47 | /** 48 | * 忽略解析JavaDoc时的错误(默认true)(未设置"-classpath",待解析的Java类中的依赖包将找不到,会产生很多错误输出,但不影响文档生成,完全可以忽略) 49 | */ 50 | private boolean ignoreJavaDocError; 51 | /** 52 | * 模板引擎配置 53 | */ 54 | private TemplateEngineConfig templateEngineConfig; 55 | /** 56 | * 文档处理器配置 57 | */ 58 | private ProcessConfig processConfig; 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/engine/AbstractTemplateEngine.java: -------------------------------------------------------------------------------- 1 | package top.naccl.engine; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import top.naccl.MainConfig; 5 | import top.naccl.util.FileUtils; 6 | 7 | import java.io.File; 8 | 9 | /** 10 | * 模板引擎抽象类 11 | * 12 | * @author: Naccl 13 | * @date: 2022-04-19 14 | */ 15 | public abstract class AbstractTemplateEngine implements TemplateEngine { 16 | /** 17 | * 主配置 18 | */ 19 | protected final MainConfig config; 20 | 21 | public AbstractTemplateEngine(MainConfig config) { 22 | this.config = config; 23 | } 24 | 25 | /** 26 | * 根据配置获取模板文件名 27 | * 28 | * @return 模板文件名 29 | */ 30 | protected String getTemplateFileName() { 31 | String customTemplatePath = config.getTemplateEngineConfig().getCustomTemplatePath(); 32 | if (StringUtils.isNotBlank(customTemplatePath) && FileUtils.isFileExists(customTemplatePath)) { 33 | //使用自定义模板 34 | return new File(customTemplatePath).getName(); 35 | } 36 | //使用自带默认模板 37 | return config.getTemplateEngineConfig().getDocumentType().getTemplateFileName() + config.getTemplateEngineConfig().getTemplateEngineType().getTemplateExtension(); 38 | } 39 | 40 | /** 41 | * 根据配置获取输出文件对象 42 | * 43 | * @return 输出文件对象 44 | */ 45 | protected File getOutputFile() { 46 | String outputPath = config.getTemplateEngineConfig().getFileOutputDir(); 47 | String outputFile = config.getTemplateEngineConfig().getFileName() + config.getTemplateEngineConfig().getDocumentType().getGenerateFileExtension(); 48 | return FileUtils.touchFile(outputPath, outputFile); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/engine/DocumentType.java: -------------------------------------------------------------------------------- 1 | package top.naccl.engine; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 文档类型 7 | * 8 | * @author: Naccl 9 | * @date: 2022-04-19 10 | */ 11 | public enum DocumentType { 12 | /** 13 | * Microsoft Word 14 | */ 15 | WORD(".doc", "document_word"), 16 | /** 17 | * HTML 18 | */ 19 | HTML(".html", "document_html"), 20 | /** 21 | * Markdown 22 | */ 23 | MARKDOWN(".md", "document_md"); 24 | 25 | /** 26 | * 生成文件后缀 27 | */ 28 | @Getter 29 | private final String generateFileExtension; 30 | /** 31 | * 模板文件名 32 | */ 33 | @Getter 34 | private final String templateFileName; 35 | 36 | DocumentType(String generateFileExtension, String templateFileName) { 37 | this.generateFileExtension = generateFileExtension; 38 | this.templateFileName = templateFileName; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/engine/TemplateEngine.java: -------------------------------------------------------------------------------- 1 | package top.naccl.engine; 2 | 3 | import top.naccl.model.ProjectModel; 4 | 5 | import java.io.IOException; 6 | 7 | /** 8 | * 模板引擎接口 9 | * 10 | * @author: Naccl 11 | * @date: 2022-04-19 12 | */ 13 | public interface TemplateEngine { 14 | /** 15 | * 生成文档 16 | * 17 | * @param model 模板数据 18 | * @throws IOException IO异常直接向上抛出 19 | */ 20 | void produce(ProjectModel model) throws IOException; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/engine/TemplateEngineConfig.java: -------------------------------------------------------------------------------- 1 | package top.naccl.engine; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | /** 9 | * 模板引擎配置 10 | * 11 | * @author: Naccl 12 | * @date: 2022-04-19 13 | */ 14 | @Data 15 | @Builder 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class TemplateEngineConfig { 19 | /** 20 | * 文档输出目录 21 | */ 22 | private String fileOutputDir; 23 | /** 24 | * 生成文档名称 25 | */ 26 | private String fileName; 27 | /** 28 | * 生成文档类型 29 | */ 30 | private DocumentType documentType; 31 | /** 32 | * 模板引擎类型 33 | */ 34 | private TemplateEngineType templateEngineType; 35 | /** 36 | * 自定义模板路径 37 | */ 38 | private String customTemplatePath; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/engine/TemplateEngineFactory.java: -------------------------------------------------------------------------------- 1 | package top.naccl.engine; 2 | 3 | import top.naccl.MainConfig; 4 | import top.naccl.engine.freemarker.FreemarkerTemplateEngine; 5 | 6 | /** 7 | * 模板引擎工厂 8 | * 9 | * @author: Naccl 10 | * @date: 2022-04-19 11 | */ 12 | public class TemplateEngineFactory { 13 | /** 14 | * 主配置 15 | */ 16 | private final MainConfig config; 17 | 18 | public TemplateEngineFactory(MainConfig config) { 19 | this.config = config; 20 | } 21 | 22 | /** 23 | * 工厂方法 24 | * 25 | * @return 模板引擎 26 | */ 27 | public TemplateEngine newInstance() { 28 | switch (config.getTemplateEngineConfig().getTemplateEngineType()) { 29 | case FREEMARKER: 30 | return new FreemarkerTemplateEngine(config); 31 | default: 32 | throw new RuntimeException("TemplateEngineType not support"); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/engine/TemplateEngineType.java: -------------------------------------------------------------------------------- 1 | package top.naccl.engine; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * 模板引擎类型 7 | * 8 | * @author: Naccl 9 | * @date: 2022-04-19 10 | */ 11 | public enum TemplateEngineType { 12 | /** 13 | * FreeMarker模板引擎 14 | */ 15 | FREEMARKER("/template/freemarker/", ".ftl"); 16 | 17 | /** 18 | * 模板文件目录 19 | */ 20 | @Getter 21 | private final String templateDir; 22 | /** 23 | * 模板文件拓展名 24 | */ 25 | @Getter 26 | private final String templateExtension; 27 | 28 | TemplateEngineType(String templateDir, String templateExtension) { 29 | this.templateDir = templateDir; 30 | this.templateExtension = templateExtension; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/engine/freemarker/FreemarkerTemplateEngine.java: -------------------------------------------------------------------------------- 1 | package top.naccl.engine.freemarker; 2 | 3 | import freemarker.cache.ClassTemplateLoader; 4 | import freemarker.template.Configuration; 5 | import freemarker.template.Template; 6 | import freemarker.template.TemplateException; 7 | import lombok.extern.slf4j.Slf4j; 8 | import org.apache.commons.lang3.StringUtils; 9 | import top.naccl.MainConfig; 10 | import top.naccl.engine.AbstractTemplateEngine; 11 | import top.naccl.model.ProjectModel; 12 | import top.naccl.util.FileUtils; 13 | 14 | import java.io.BufferedWriter; 15 | import java.io.File; 16 | import java.io.FileOutputStream; 17 | import java.io.IOException; 18 | import java.io.OutputStreamWriter; 19 | import java.io.Writer; 20 | import java.nio.charset.StandardCharsets; 21 | import java.util.Locale; 22 | 23 | /** 24 | * Freemarker模板引擎 25 | * 26 | * @author: Naccl 27 | * @date: 2022-04-19 28 | */ 29 | @Slf4j 30 | public class FreemarkerTemplateEngine extends AbstractTemplateEngine { 31 | /** 32 | * Freemarker配置 33 | */ 34 | private final Configuration freemarkerConfig; 35 | 36 | /** 37 | * 初始化Freemarker模板引擎配置 38 | * 39 | * @param config 主配置 40 | */ 41 | public FreemarkerTemplateEngine(MainConfig config) { 42 | super(config); 43 | freemarkerConfig = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); 44 | 45 | String customTemplatePath = config.getTemplateEngineConfig().getCustomTemplatePath(); 46 | if (StringUtils.isNotBlank(customTemplatePath) && FileUtils.isFileExists(customTemplatePath)) { 47 | //使用自定义模板 48 | File parentPath = new File(customTemplatePath).getParentFile(); 49 | try { 50 | //设置模板加载路径 51 | freemarkerConfig.setDirectoryForTemplateLoading(parentPath); 52 | } catch (IOException e) { 53 | log.error("An exception occurred during custom Freemarker template engine configuration:", e); 54 | } 55 | } else { 56 | //使用自带模板 57 | freemarkerConfig.setTemplateLoader(new ClassTemplateLoader(this.getClass(), config.getTemplateEngineConfig().getTemplateEngineType().getTemplateDir())); 58 | } 59 | 60 | freemarkerConfig.setDefaultEncoding("UTF-8"); 61 | freemarkerConfig.setLocale(Locale.SIMPLIFIED_CHINESE); 62 | } 63 | 64 | /** 65 | * 生成文档 66 | * 67 | * @param model 模板数据 68 | * @throws IOException IO异常直接向上抛出 69 | */ 70 | @Override 71 | public void produce(ProjectModel model) throws IOException { 72 | Template template = freemarkerConfig.getTemplate(getTemplateFileName()); 73 | File file = getOutputFile(); 74 | 75 | try (Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8))) { 76 | template.process(model, out); 77 | } catch (TemplateException e) { 78 | log.error("An exception occurred during Freemarker template engine processing:", e); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/execute/DocumentExecute.java: -------------------------------------------------------------------------------- 1 | package top.naccl.execute; 2 | 3 | import com.sun.javadoc.RootDoc; 4 | import lombok.extern.slf4j.Slf4j; 5 | import top.naccl.MainConfig; 6 | import top.naccl.engine.TemplateEngine; 7 | import top.naccl.engine.TemplateEngineFactory; 8 | import top.naccl.model.ProjectModel; 9 | import top.naccl.process.ProjectModelProcessor; 10 | import top.naccl.process.RootDocProcessor; 11 | import top.naccl.reader.JavaDocReader; 12 | import top.naccl.util.CollectionUtils; 13 | import top.naccl.util.FileUtils; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * 文档生成执行器 21 | * 22 | * @author: Naccl 23 | * @date: 2022-04-19 24 | */ 25 | @Slf4j 26 | public class DocumentExecute { 27 | /** 28 | * 主配置 29 | */ 30 | private final MainConfig config; 31 | 32 | public DocumentExecute(MainConfig config) { 33 | this.config = config; 34 | } 35 | 36 | /** 37 | * 执行文档生成 38 | */ 39 | public void execute() { 40 | try { 41 | long start = System.currentTimeMillis(); 42 | List javaFiles = getJavaFiles(config.getProjectPaths(), config.getMaxDepth()); 43 | if (CollectionUtils.isEmpty(javaFiles)) { 44 | log.warn("No Java files were found in the path you input"); 45 | return; 46 | } 47 | log.info("The number of Java files found in the path you input is: {}", javaFiles.size()); 48 | 49 | parseJavaDoc(javaFiles); 50 | 51 | ProjectModel projectModel = new ProjectModelProcessor(config).process(); 52 | log.debug("The ProjectModel is: {}", projectModel); 53 | 54 | TemplateEngine templateEngine = new TemplateEngineFactory(config).newInstance(); 55 | templateEngine.produce(projectModel); 56 | 57 | log.info("The document was generated successfully, the time consumed is: {}ms", System.currentTimeMillis() - start); 58 | } catch (IOException e) { 59 | log.error("The document was generated failed, the error is:", e); 60 | } 61 | } 62 | 63 | /** 64 | * 遍历给定路径中的Java文件 65 | * 66 | * @param pathList 路径列表 67 | * @param maxDepth 最大深度 68 | * @return java文件列表 69 | */ 70 | private List getJavaFiles(List pathList, int maxDepth) throws IOException { 71 | List javaFiles = new ArrayList<>(); 72 | for (String path : pathList) { 73 | if (!FileUtils.isFileExists(path)) { 74 | log.error("One of the project path to be generated does not exist, the absolute path you input is: {}", FileUtils.getCanonicalPath(path)); 75 | return null; 76 | } 77 | log.info("The project path to be generated is: {}", FileUtils.getCanonicalPath(path)); 78 | javaFiles.addAll(FileUtils.walkJavaFile(path, maxDepth)); 79 | } 80 | return javaFiles; 81 | } 82 | 83 | /** 84 | * 解析JavaDoc 85 | * 86 | * @param javaFiles 待解析的Java文件列表 87 | */ 88 | private void parseJavaDoc(List javaFiles) { 89 | RootDocProcessor rootDocProcessor = new RootDocProcessor(config); 90 | javaFiles.forEach(file -> { 91 | RootDoc rootDoc = JavaDocReader.read(file, config); 92 | if (rootDocProcessor.setRootDoc(rootDoc)) { 93 | rootDocProcessor.process(); 94 | } 95 | }); 96 | log.info("Parse JavaDoc DONE"); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/model/ClassModel.java: -------------------------------------------------------------------------------- 1 | package top.naccl.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 类信息 11 | * 12 | * @author: Naccl 13 | * @date: 2022-04-18 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class ClassModel { 19 | /** 20 | * 类名 21 | */ 22 | private String name; 23 | /** 24 | * 类中的字段 25 | */ 26 | private List fieldList; 27 | /** 28 | * 类中的方法 29 | */ 30 | private List methodList; 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/model/FieldModel.java: -------------------------------------------------------------------------------- 1 | package top.naccl.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 字段信息 9 | * 10 | * @author: Naccl 11 | * @date: 2022-04-18 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class FieldModel { 17 | /** 18 | * 访问修饰符 19 | */ 20 | private String accessModifier; 21 | /** 22 | * 字段名 23 | */ 24 | private String name; 25 | /** 26 | * 字段类型 27 | */ 28 | private String type; 29 | /** 30 | * JavaDoc注释 31 | */ 32 | private String comment; 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/model/MethodModel.java: -------------------------------------------------------------------------------- 1 | package top.naccl.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 方法信息 11 | * 12 | * @author: Naccl 13 | * @date: 2022-04-18 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class MethodModel { 19 | /** 20 | * 访问修饰符 21 | */ 22 | private String accessModifier; 23 | /** 24 | * 方法名 25 | */ 26 | private String name; 27 | /** 28 | * 返回类型 29 | */ 30 | private String returnType; 31 | /** 32 | * JavaDoc注释 33 | */ 34 | private String comment; 35 | /** 36 | * 参数列表 37 | */ 38 | private List paramList; 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/model/PackageModel.java: -------------------------------------------------------------------------------- 1 | package top.naccl.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 包信息 11 | * 12 | * @author: Naccl 13 | * @date: 2022-04-18 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class PackageModel { 19 | /** 20 | * 包名 21 | */ 22 | private String name; 23 | /** 24 | * 包中所有的类 25 | */ 26 | private List classList; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/model/ParamModel.java: -------------------------------------------------------------------------------- 1 | package top.naccl.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | /** 8 | * 参数信息 9 | * 10 | * @author: Naccl 11 | * @date: 2022-04-18 12 | */ 13 | @Data 14 | @NoArgsConstructor 15 | @AllArgsConstructor 16 | public class ParamModel { 17 | /** 18 | * 参数名称 19 | */ 20 | private String name; 21 | /** 22 | * 参数类型 23 | */ 24 | private String type; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/model/ProjectModel.java: -------------------------------------------------------------------------------- 1 | package top.naccl.model; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * 项目信息 11 | * 12 | * @author: Naccl 13 | * @date: 2022-04-18 14 | */ 15 | @Data 16 | @NoArgsConstructor 17 | @AllArgsConstructor 18 | public class ProjectModel { 19 | /** 20 | * 项目名称 21 | */ 22 | private String projectName; 23 | /** 24 | * 文档版本 25 | */ 26 | private String version; 27 | /** 28 | * 文档描述 29 | */ 30 | private String description; 31 | /** 32 | * 项目中所有的包 33 | */ 34 | private List packageList; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/process/AbstractProcessor.java: -------------------------------------------------------------------------------- 1 | package top.naccl.process; 2 | 3 | import top.naccl.MainConfig; 4 | import top.naccl.model.PackageModel; 5 | 6 | import java.util.LinkedHashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * 处理器抽象类 11 | * 12 | * @author: Naccl 13 | * @date: 2022-04-19 14 | */ 15 | public abstract class AbstractProcessor { 16 | /** 17 | * 包名和包信息的映射 18 | */ 19 | protected static Map packageMap = new LinkedHashMap<>(); 20 | /** 21 | * 主配置 22 | */ 23 | protected MainConfig config; 24 | 25 | protected AbstractProcessor(MainConfig config) { 26 | this.config = config; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/process/ProcessConfig.java: -------------------------------------------------------------------------------- 1 | package top.naccl.process; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * 处理器配置 12 | * 13 | * @author: Naccl 14 | * @date: 2022-04-19 15 | */ 16 | @Data 17 | @Builder 18 | @NoArgsConstructor 19 | @AllArgsConstructor 20 | public class ProcessConfig { 21 | /** 22 | * 是否显示访问修饰符(字段、方法) 23 | */ 24 | private boolean displayAccessModifier; 25 | /** 26 | * 忽略没有字段和方法的类 27 | */ 28 | private boolean ignoreClassWithoutFieldAndMethod; 29 | /** 30 | * 忽略没有JavaDoc注释的字段 31 | */ 32 | private boolean ignoreFieldWithoutComment; 33 | /** 34 | * 忽略没有JavaDoc注释的方法 35 | */ 36 | private boolean ignoreMethodWithoutComment; 37 | /** 38 | * 忽略包名前缀 39 | */ 40 | private List ignorePackagePrefix; 41 | /** 42 | * 忽略包名后缀 43 | */ 44 | private List ignorePackageSuffix; 45 | /** 46 | * 忽略类名前缀 47 | */ 48 | private List ignoreClassPrefix; 49 | /** 50 | * 忽略类名后缀 51 | */ 52 | private List ignoreClassSuffix; 53 | /** 54 | * 忽略字段名前缀 55 | */ 56 | private List ignoreFieldPrefix; 57 | /** 58 | * 忽略字段名后缀 59 | */ 60 | private List ignoreFieldSuffix; 61 | /** 62 | * 忽略方法名前缀 63 | */ 64 | private List ignoreMethodPrefix; 65 | /** 66 | * 忽略方法名后缀 67 | */ 68 | private List ignoreMethodSuffix; 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/process/ProjectModelProcessor.java: -------------------------------------------------------------------------------- 1 | package top.naccl.process; 2 | 3 | import top.naccl.MainConfig; 4 | import top.naccl.model.ProjectModel; 5 | 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * 数据模型处理器 10 | * 11 | * @author: Naccl 12 | * @date: 2022-04-18 13 | */ 14 | public class ProjectModelProcessor extends AbstractProcessor { 15 | public ProjectModelProcessor(MainConfig config) { 16 | super(config); 17 | } 18 | 19 | /** 20 | * 生成数据模型 21 | * 22 | * @return 数据模型 23 | */ 24 | public ProjectModel process() { 25 | ProjectModel projectModel = new ProjectModel(); 26 | projectModel.setProjectName(config.getProjectName()); 27 | projectModel.setVersion(config.getVersion()); 28 | projectModel.setDescription(config.getDescription()); 29 | projectModel.setPackageList(new ArrayList<>(packageMap.values())); 30 | return projectModel; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/process/RootDocProcessor.java: -------------------------------------------------------------------------------- 1 | package top.naccl.process; 2 | 3 | import com.sun.javadoc.ClassDoc; 4 | import com.sun.javadoc.Doc; 5 | import com.sun.javadoc.FieldDoc; 6 | import com.sun.javadoc.MethodDoc; 7 | import com.sun.javadoc.Parameter; 8 | import com.sun.javadoc.ProgramElementDoc; 9 | import com.sun.javadoc.RootDoc; 10 | import lombok.extern.slf4j.Slf4j; 11 | import org.apache.commons.text.StringEscapeUtils; 12 | import top.naccl.MainConfig; 13 | import top.naccl.model.ClassModel; 14 | import top.naccl.model.FieldModel; 15 | import top.naccl.model.MethodModel; 16 | import top.naccl.model.PackageModel; 17 | import top.naccl.model.ParamModel; 18 | import top.naccl.util.CollectionUtils; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | /** 24 | * JavaDoc处理器 25 | * 26 | * @author: Naccl 27 | * @date: 2022-04-18 28 | */ 29 | @Slf4j 30 | public class RootDocProcessor extends AbstractProcessor { 31 | /** 32 | * JavaDoc中的未知类型 33 | */ 34 | private static final String UNKNOWN_TYPE = ""; 35 | /** 36 | * JavaDoc中的未知类型的替代显示 37 | */ 38 | private static final String UNKNOWN_TYPE_REPLACE = "T"; 39 | /** 40 | * 待处理的JavaDoc 41 | */ 42 | private RootDoc rootDoc; 43 | /** 44 | * 处理计数 45 | */ 46 | private int count = 0; 47 | /** 48 | * 处理器配置 49 | */ 50 | private final ProcessConfig processConfig; 51 | 52 | public RootDocProcessor(MainConfig config) { 53 | super(config); 54 | this.processConfig = config.getProcessConfig(); 55 | } 56 | 57 | /** 58 | * 将JavaDoc设置到处理器中 59 | * 60 | * @param rootDoc JavaDoc 61 | * @return 是否成功 62 | */ 63 | public boolean setRootDoc(RootDoc rootDoc) { 64 | //判断RootDoc是否为空,判断和上一次设置的是否是同一个对象,如果是,则可能是JavaDoc解析失败,直接返回false跳过这个 65 | if (rootDoc == null || rootDoc.equals(this.rootDoc)) { 66 | log.warn("RootDocProcessor.setRootDoc: rootDoc is the same, ignore"); 67 | return false; 68 | } 69 | this.rootDoc = rootDoc; 70 | this.count++; 71 | log.info("Java file count: {}, classes: {}", count, this.rootDoc.classes()); 72 | return true; 73 | } 74 | 75 | /** 76 | * 转换JavaDoc到数据模型 77 | */ 78 | public void process() { 79 | if (this.rootDoc != null) { 80 | ClassDoc[] classes = this.rootDoc.classes(); 81 | for (ClassDoc classDoc : classes) { 82 | String packageName = classDoc.containingPackage().name(); 83 | 84 | if (isIgnoreWithPrefixOrSuffix(packageName, processConfig.getIgnorePackagePrefix(), processConfig.getIgnorePackageSuffix())) { 85 | //忽略包 86 | continue; 87 | } 88 | if (isIgnoreWithPrefixOrSuffix(classDoc.name(), processConfig.getIgnoreClassPrefix(), processConfig.getIgnoreClassSuffix())) { 89 | //忽略类 90 | continue; 91 | } 92 | 93 | List fieldList = new ArrayList<>(); 94 | List methodList = new ArrayList<>(); 95 | 96 | for (FieldDoc fieldDoc : classDoc.fields()) { 97 | String comment = getDocComment(fieldDoc); 98 | if (processConfig.isIgnoreFieldWithoutComment() && comment.length() == 0) { 99 | //忽略没有注释的字段 100 | continue; 101 | } 102 | if (isIgnoreWithPrefixOrSuffix(fieldDoc.name(), processConfig.getIgnoreFieldPrefix(), processConfig.getIgnoreFieldSuffix())) { 103 | //忽略字段 104 | continue; 105 | } 106 | 107 | FieldModel fieldModel = new FieldModel(getAccessModifier(fieldDoc), fieldDoc.name(), replaceUnknownType(fieldDoc.type().typeName()), comment); 108 | fieldList.add(fieldModel); 109 | } 110 | 111 | for (MethodDoc methodDoc : classDoc.methods()) { 112 | String comment = getDocComment(methodDoc); 113 | if (processConfig.isIgnoreMethodWithoutComment() && comment.length() == 0) { 114 | //忽略没有注释的方法 115 | continue; 116 | } 117 | if (isIgnoreWithPrefixOrSuffix(methodDoc.name(), processConfig.getIgnoreMethodPrefix(), processConfig.getIgnoreMethodSuffix())) { 118 | //忽略方法 119 | continue; 120 | } 121 | 122 | List paramList = new ArrayList<>(); 123 | for (Parameter parameter : methodDoc.parameters()) { 124 | ParamModel paramModel = new ParamModel(parameter.name(), replaceUnknownType(parameter.typeName())); 125 | paramList.add(paramModel); 126 | } 127 | 128 | MethodModel methodModel = new MethodModel(getAccessModifier(methodDoc), methodDoc.name(), replaceUnknownType(methodDoc.returnType().typeName()), comment, paramList); 129 | methodList.add(methodModel); 130 | } 131 | if (isIgnoreClass(fieldList, methodList)) { 132 | //忽略没有字段和方法的类 133 | continue; 134 | } 135 | ClassModel classModel = new ClassModel(classDoc.name(), fieldList, methodList); 136 | if (!packageMap.containsKey(packageName)) { 137 | //该包名不存在,创建 138 | PackageModel packageModel = new PackageModel(packageName, new ArrayList<>()); 139 | packageMap.put(packageName, packageModel); 140 | } 141 | packageMap.get(packageName).getClassList().add(classModel); 142 | } 143 | } 144 | } 145 | 146 | /** 147 | * 判断给定的字符串是否包含在前缀或后缀List中 148 | * 149 | * @param str 待判断的字符串 150 | * @param prefixList 前缀List 151 | * @param suffixList 后缀List 152 | * @return 是否包含 153 | */ 154 | private boolean isIgnoreWithPrefixOrSuffix(String str, List prefixList, List suffixList) { 155 | if (CollectionUtils.isNotEmpty(prefixList)) { 156 | for (String prefix : prefixList) { 157 | if (str.startsWith(prefix)) { 158 | return true; 159 | } 160 | } 161 | } 162 | if (CollectionUtils.isNotEmpty(suffixList)) { 163 | for (String suffix : suffixList) { 164 | if (str.endsWith(suffix)) { 165 | return true; 166 | } 167 | } 168 | } 169 | return false; 170 | } 171 | 172 | /** 173 | * 判断是否要忽略没有字段和方法的类 174 | * 175 | * @param fieldList 字段列表 176 | * @param methodList 方法列表 177 | * @return 是否忽略 178 | */ 179 | private boolean isIgnoreClass(List fieldList, List methodList) { 180 | return processConfig.isIgnoreClassWithoutFieldAndMethod() && fieldList.size() == 0 && methodList.size() == 0; 181 | } 182 | 183 | /** 184 | * 获取访问修饰符 185 | * 186 | * @param doc JavaDoc 187 | * @param {@link ProgramElementDoc} 188 | * @return 访问修饰符 189 | */ 190 | private String getAccessModifier(T doc) { 191 | if (processConfig.isDisplayAccessModifier()) { 192 | if (doc.isPublic()) { 193 | return "public"; 194 | } else if (doc.isPrivate()) { 195 | return "private"; 196 | } else if (doc.isProtected()) { 197 | return "protected"; 198 | } 199 | } 200 | return ""; 201 | } 202 | 203 | /** 204 | * 替换未知类型 205 | * 206 | * @param typeName 类型名称 207 | * @return {@link RootDocProcessor#UNKNOWN_TYPE_REPLACE} 208 | */ 209 | private String replaceUnknownType(String typeName) { 210 | return typeName.replaceAll(UNKNOWN_TYPE, UNKNOWN_TYPE_REPLACE); 211 | } 212 | 213 | /** 214 | * 获取并处理注释中的特殊字符 215 | * 216 | * @param doc {@link Doc} 需要获取注释的Doc节点 217 | * @param {@link Doc} Doc的子类 218 | * @return 处理后的注释 219 | */ 220 | private String getDocComment(T doc) { 221 | String comment = doc.commentText().trim(); 222 | comment = comment.replaceAll("

", " "); 223 | //将多个连续的空白字符替换成一个空格 224 | comment = comment.replaceAll("\\s+", " "); 225 | //转义xml字符 226 | return StringEscapeUtils.escapeXml10(comment); 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/reader/JavaDocReader.java: -------------------------------------------------------------------------------- 1 | package top.naccl.reader; 2 | 3 | import com.sun.javadoc.RootDoc; 4 | import top.naccl.MainConfig; 5 | 6 | import java.io.OutputStream; 7 | import java.io.PrintWriter; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | /** 12 | * JavaDocReader 13 | * 14 | * @author: Naccl 15 | * @date: 2022-04-18 16 | */ 17 | public class JavaDocReader { 18 | /** 19 | * 解析出的JavaDoc结果 20 | */ 21 | private static RootDoc root; 22 | 23 | public static class Doclet { 24 | /** 25 | * The main entry point of the doclet. 26 | * 27 | * @param root the root of the documentation tree 28 | * @return true if the doclet processed the documentation 29 | */ 30 | @SuppressWarnings("unused") 31 | public static boolean start(RootDoc root) { 32 | JavaDocReader.root = root; 33 | return true; 34 | } 35 | } 36 | 37 | /** 38 | * 读取JavaDoc 39 | * 40 | * @param javaFilePath java文件路径 41 | * @param config 主配置 42 | * @return 读取结果 43 | */ 44 | public static RootDoc read(String javaFilePath, MainConfig config) { 45 | return read(javaFilePath, config.isIncludePrivate(), config.isIgnoreJavaDocError()); 46 | } 47 | 48 | /** 49 | * 读取JavaDoc 50 | * 51 | * @param javaFilePath java文件路径 52 | * @param readAll 是否读取所有的类和成员(包括private) 53 | * @param ignoreError 是否忽略错误(未设置"-classpath",待解析的Java类中的依赖包将找不到,会产生很多错误输出,但不影响文档生成,完全可以忽略) 54 | * @return 读取结果 55 | */ 56 | public static RootDoc read(String javaFilePath, boolean readAll, boolean ignoreError) { 57 | List args = new ArrayList<>(); 58 | args.add("-encoding"); 59 | args.add("utf-8"); 60 | args.add(javaFilePath); 61 | if (readAll) { 62 | args.add("-private"); 63 | } 64 | 65 | PrintWriter out; 66 | if (ignoreError) { 67 | //忽略错误,将输出流设置为无操作 68 | out = new PrintWriter(new OutputStream() { 69 | @Override 70 | public void write(int b) { 71 | } 72 | }); 73 | } else { 74 | out = new PrintWriter(System.err); 75 | } 76 | 77 | com.sun.tools.javadoc.Main.execute("Java2Doc", out, out, out, Doclet.class.getName(), args.toArray(new String[0])); 78 | return root; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/util/CollectionUtils.java: -------------------------------------------------------------------------------- 1 | package top.naccl.util; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * 集合工具类 7 | * 8 | * @author: Naccl 9 | * @date: 2022-04-19 10 | */ 11 | public class CollectionUtils { 12 | /** 13 | * 集合是否为空 14 | * 15 | * @param collection 集合 16 | * @return 是否为空 17 | */ 18 | public static boolean isEmpty(Collection collection) { 19 | return collection == null || collection.isEmpty(); 20 | } 21 | 22 | /** 23 | * 集合是否为非空 24 | * 25 | * @param collection 集合 26 | * @return 是否为非空 27 | */ 28 | public static boolean isNotEmpty(Collection collection) { 29 | return !isEmpty(collection); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/util/FileUtils.java: -------------------------------------------------------------------------------- 1 | package top.naccl.util; 2 | 3 | import lombok.SneakyThrows; 4 | 5 | import java.io.File; 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.nio.file.Paths; 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | import java.util.stream.Stream; 13 | 14 | /** 15 | * 文件工具类 16 | * 17 | * @author: Naccl 18 | * @date: 2022-04-18 19 | */ 20 | public class FileUtils { 21 | /** 22 | * 获取当前路径 23 | * 24 | * @return 当前路径 25 | */ 26 | public static String getCurrentPath() { 27 | return System.getProperty("user.dir"); 28 | } 29 | 30 | /** 31 | * 检查文件或目录是否存在 32 | * 33 | * @param path 文件或目录路径 34 | * @return 存在返回true,否则返回false 35 | */ 36 | public static boolean isFileExists(String path) { 37 | return Files.exists(Paths.get(path)); 38 | } 39 | 40 | /** 41 | * 获取绝对路径 42 | * 43 | * @param path 路径 44 | * @return 绝对路径 45 | */ 46 | @SneakyThrows 47 | public static String getCanonicalPath(String path) { 48 | File file = new File(path); 49 | return file.getCanonicalPath(); 50 | } 51 | 52 | /** 53 | * 创建文件 54 | * 55 | * @param path 文件路径 56 | * @param fileName 文件名 57 | * @return File Object 58 | */ 59 | public static File touchFile(String path, String fileName) { 60 | File folder = new File(path); 61 | folder.mkdirs(); 62 | return new File(folder, fileName); 63 | } 64 | 65 | /** 66 | * 遍历给定根目录下的所有指定拓展名文件 67 | * 68 | * @param rootPath 根目录 69 | * @param maxDepth 最大深度 70 | * @param fileExtension 文件拓展名 71 | * @return 指定拓展名文件列表 72 | * @throws IOException 出现IO异常则抛出 73 | */ 74 | public static List walkFile(String rootPath, int maxDepth, String fileExtension) throws IOException { 75 | List javaFiles = new ArrayList<>(); 76 | Stream paths = Files.walk(Paths.get(rootPath), maxDepth); 77 | paths.map(Path::toString).filter(f -> f.endsWith(fileExtension)).forEach(javaFiles::add); 78 | return javaFiles; 79 | } 80 | 81 | /** 82 | * 遍历给定根目录下的所有.java文件 83 | * 84 | * @param rootPath 根目录 85 | * @param maxDepth 最大深度 86 | * @return java文件列表 87 | * @throws IOException 出现IO异常则抛出 88 | */ 89 | public static List walkJavaFile(String rootPath, int maxDepth) throws IOException { 90 | return walkFile(rootPath, maxDepth, ".java"); 91 | } 92 | 93 | /** 94 | * 遍历给定根目录下的所有.java文件 95 | * 96 | * @param rootPath 根目录 97 | * @return java文件列表 98 | * @throws IOException 出现IO异常则抛出 99 | */ 100 | public static List walkJavaFile(String rootPath) throws IOException { 101 | return walkJavaFile(rootPath, Integer.MAX_VALUE); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/top/naccl/util/PropertiesUtils.java: -------------------------------------------------------------------------------- 1 | package top.naccl.util; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import java.io.IOException; 6 | import java.io.InputStream; 7 | import java.util.Properties; 8 | 9 | /** 10 | * 配置文件工具类 11 | * 12 | * @author: Naccl 13 | * @date: 2022-04-21 14 | */ 15 | @Slf4j 16 | public class PropertiesUtils { 17 | /** 18 | * 配置文件 19 | */ 20 | private static Properties properties; 21 | 22 | /** 23 | * 加载配置文件 24 | */ 25 | static { 26 | properties = new Properties(); 27 | try (InputStream inputStream = PropertiesUtils.class.getClassLoader().getResourceAsStream("app.properties")) { 28 | properties.load(inputStream); 29 | } catch (IOException e) { 30 | log.error("An exception occurred during the loading of app.properties", e); 31 | } 32 | } 33 | 34 | /** 35 | * 获取配置文件中的值 36 | * 37 | * @param key 配置文件中的key 38 | * @return 配置文件中的value 39 | */ 40 | public static String getProperty(String key) { 41 | return properties.getProperty(key); 42 | } 43 | 44 | /** 45 | * 获取版本号 46 | * 47 | * @return 版本号 48 | */ 49 | public static String getVersion() { 50 | return properties.getProperty("java2doc.version"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/resources/app.properties: -------------------------------------------------------------------------------- 1 | java2doc.version=1.0.0 2 | -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/1.8/tools-1.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Naccl/Java2Doc/a928088c86aab9459f989b0a50d0de6270e547fd/src/main/resources/lib/com/sun/tools/1.8/tools-1.8.jar -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/1.8/tools-1.8.jar.md5: -------------------------------------------------------------------------------- 1 | 2900dd94c85ab07fb0c977bc3f918c60 -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/1.8/tools-1.8.jar.sha1: -------------------------------------------------------------------------------- 1 | 81a753eb87560f9f734cf3b33d6154d638cddf15 -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/1.8/tools-1.8.pom: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.sun 6 | tools 7 | 1.8 8 | POM was created from install:install-file 9 | 10 | -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/1.8/tools-1.8.pom.md5: -------------------------------------------------------------------------------- 1 | 1b4991223deec9771c82b50d7dc219ce -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/1.8/tools-1.8.pom.sha1: -------------------------------------------------------------------------------- 1 | 656a05f70988c494c934ab15f00d345866d0f0bf -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/maven-metadata-local.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | com.sun 4 | tools 5 | 6 | 1.8 7 | 8 | 1.8 9 | 10 | 20220422001826 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/maven-metadata-local.xml.md5: -------------------------------------------------------------------------------- 1 | 36b1bd779f77e1e2347264e82a25547d -------------------------------------------------------------------------------- /src/main/resources/lib/com/sun/tools/maven-metadata-local.xml.sha1: -------------------------------------------------------------------------------- 1 | 608ee709c975b64a7600c6cc24cc23e723bdce05 -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ${log.pattern} 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/main/resources/template/freemarker/document_html.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 126 | ${projectName!'Java2Doc'} 127 | 128 | 129 |

Java Class描述文档

130 |

项目名称:${projectName!'Java2Doc'}

131 |

文档版本:${version!'1.0.0'}

132 |

文档描述:${description!'Java项目Class描述文档生成'}

133 | <#list packageList as package> 134 |

${package.name}包中类的描述

135 |
136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | <#list package.classList as class> 146 | <#if class.fieldList?size == 0 && class.methodList?size == 0> 147 | <#--如果字段和方法都没有,就保留个类名--> 148 | 149 | 150 | 151 | 152 | 153 | 154 | <#list class.fieldList as field> 155 | <#if field_index == 0> 156 | <#--第一行--> 157 | 158 | 159 | 160 | 161 | 162 | <#else> 163 | <#--第一行之后--> 164 | 165 | 166 | 167 | 168 | 169 | 170 | <#list class.methodList as method> 171 | <#if class.fieldList?size == 0 && method_index == 0> 172 | <#--第一行--> 173 | 174 | 175 | 176 | 177 | 178 | <#else> 179 | <#--第一行之后--> 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 |
类名属性/方法描述
${class.name}
${class.name}<#if field.accessModifier!=''>${field.accessModifier} ${field.type} ${field.name};${field.comment}
<#if field.accessModifier!=''>${field.accessModifier} ${field.type} ${field.name};${field.comment}
${class.name}<#if method.accessModifier!=''>${method.accessModifier} ${method.returnType} ${method.name}(<#list method.paramList as param>${param.type} ${param.name}<#if param_has_next>, );${method.comment}
<#if method.accessModifier!=''>${method.accessModifier} ${method.returnType} ${method.name}(<#list method.paramList as param>${param.type} ${param.name}<#if param_has_next>, );${method.comment}
189 |
190 | 191 | 192 | -------------------------------------------------------------------------------- /src/main/resources/template/freemarker/document_md.ftl: -------------------------------------------------------------------------------- 1 | # Java Class描述文档 2 | 3 | **项目名称**:${projectName!'Java2Doc'} 4 | 5 | **文档版本**:${version!'1.0.0'} 6 | 7 | **文档描述**:${description!'Java项目Class描述文档生成'} 8 | <#list packageList as package> 9 | 10 | #### ${package.name}包中类的描述 11 | 12 | | 类名 | 属性/方法 | 描述 | 13 | |:---:|---|---| 14 | <#list package.classList as class> 15 | <#if class.fieldList?size == 0 && class.methodList?size == 0> 16 | <#--如果字段和方法都没有,就保留个类名--> 17 | | ${class.name} | | | 18 | 19 | <#list class.fieldList as field> 20 | <#if field_index == 0> 21 | <#--第一行--> 22 | | ${class.name} | <#if field.accessModifier!=''>${field.accessModifier} ${field.type} ${field.name}; | ${field.comment} | 23 | <#else> 24 | <#--第一行之后--> 25 | | | <#if field.accessModifier!=''>${field.accessModifier} ${field.type} ${field.name}; | ${field.comment} | 26 | 27 | 28 | <#list class.methodList as method> 29 | <#if class.fieldList?size == 0 && method_index == 0> 30 | <#--第一行--> 31 | | ${class.name} | <#if method.accessModifier!=''>${method.accessModifier} ${method.returnType} ${method.name}(<#list method.paramList as param>${param.type} ${param.name}<#if param_has_next>, ); | ${method.comment} | 32 | <#else> 33 | <#--第一行之后--> 34 | | | <#if method.accessModifier!=''>${method.accessModifier} ${method.returnType} ${method.name}(<#list method.paramList as param>${param.type} ${param.name}<#if param_has_next>, ); | ${method.comment} | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/main/resources/template/freemarker/document_word.ftl: -------------------------------------------------------------------------------- 1 | <#--标题-->Java Class描述文档<#--项目名称-->项目名称:${projectName!'Java2Doc'}<#--文档版本-->文档版本:${version!'1.0.0'}<#--文档描述-->文档描述:${description!'Java项目Class描述文档生成'}<#--循环从这里开始--><#list packageList as package><#--小标题-->${package.name}包中类的描述<#--表格描述-->表${package_index + 1} ${package.name}包中类的描述<#--表格--><#--表头--><#--类名-->类名<#--属性/方法-->属性/方法<#--描述-->描述<#--表格行--><#list package.classList as class><#if class.fieldList?size == 0 && class.methodList?size == 0><#--如果字段和方法都没有,就保留个类名--><#--单元格1,第一行用这个w:tc-->${class.name}<#--单元格2--><#--留空--><#--单元格3--><#--留空--><#list class.fieldList as field><#if field_index == 0><#--单元格1,第一行用这个w:tc-->${class.name}<#else><#--单元格1,第一行之后用这个w:tc--><#--单元格2--><#if field.accessModifier!=''>${field.accessModifier} ${field.type} ${field.name};<#--单元格3-->${field.comment}<#list class.methodList as method><#if class.fieldList?size == 0 && method_index == 0><#--单元格1,第一行用这个w:tc-->${class.name}<#else><#--单元格1,第一行之后用这个w:tc--><#--单元格2--><#if method.accessModifier!=''>${method.accessModifier} ${method.returnType} ${method.name}(<#list method.paramList as param>${param.type} ${param.name}<#if param_has_next>, );<#--单元格3-->${method.comment}<#--循环到这里结束-->${projectName!'Java2Doc'}NacclNaccl10111Microsoft Office Word011falsefalse0falsefalse16.0000 --------------------------------------------------------------------------------