Write documentation
As a developer, everyone has to write code.
At work, almost every developer has to write documentation.
Because work is a collaboration between people, requirements documents must be written for products, detailed design documents and interface documents must be written for development.
However, as a lazy person, one of the most annoying things is writing documents.
The most uncomfortable part of writing the document is that the code remarks need to be changed again, and then the document is changed again.
All repetitive work is the biggest waste of our precious fishing time.
So, I often think, can I just write it once?
i-doc project introduction
idoc generates project documentation for java projects.
Based on native java annotations, generate brief documentation as much as possible. Users can customize their own templates to generate the documents they need.
Implementation principle: based on maven plug-in, similar to javadoc. Can be more flexible, allowing user customization.
characteristic
(1) Generate metadata containing most of the information based on the maven project
(2) Support markdown by default to simplify document generation and support custom templates
(3) Support user-defined document generator
(4) Support user-defined class filters for generating documents
(5) Add field type aliases, support user customization
Quick start
need
jdk1.8+
maven 3.x+
Introduced by maven
Use maven to import the current idoc plugin.
<build>
<plugins>
<plugin>
<groupId>com.github.houbb</groupId>
<artifactId>idoc-core</artifactId>
<version>0.3.0</version>
</plugin>
</plugins>
</build>
Creation of test objects
To demonstrate the document, we created an Address object.
package com.github.houbb.idoc.test.model;
/**
* 地址
* @author binbin.hou
* @since 0.0.1
*/
public class Address {
/**
* 城市
*/
private String country;
/**
* 街道
*/
private String street;
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
Execution plugin
mvn com.github.houbb:idoc-core:0.3.0:idoc
Command line log information
[INFO] ------------------------------------ Start generate doc
[INFO] 共计 【1】 个文件待处理,请耐心等待。进度如下:
==================================================================================================== 100%
[INFO] Generator doc with docGenerator: com.github.houbb.idoc.core.api.generator.ConsoleDocGenerator
[INFO] ------------------------------------ 文档信息如下:
[类名] com.github.houbb.idoc.test.model.Address
[类信息] {"comment":"地址","docAnnotationList":[],"docFieldList":[{"comment":"城市","name":"country","type":"java.lang.String"},{"comment":"街道","name":"street","type":"java.lang.String"}],"docMethodList":[{"docMethodParameterList":[],"docMethodReturn":{"fullName":"java.lang.String","name":"String","packageName":"java.lang"},"docTagList":[],"exceptionList":[],"modifiers":["public"],"name":"getCountry","seeList":[],"signature":"getCountry()"},{"docMethodParameterList":[{"docAnnotationList":[],"name":"country","type":"java.lang.String"}],"docMethodReturn":{},"docTagList":[],"exceptionList":[],"modifiers":["public"],"name":"setCountry","seeList":[],"signature":"setCountry(country)"},{"docMethodParameterList":[],"docMethodReturn":{"fullName":"java.lang.String","name":"String","packageName":"java.lang"},"docTagList":[],"exceptionList":[],"modifiers":["public"],"name":"getStreet","seeList":[],"signature":"getStreet()"},{"docMethodParameterList":[{"docAnnotationList":[],"name":"street","type":"java.lang.String"}],"docMethodReturn":{},"docTagList":[],"exceptionList":[],"modifiers":["public"],"name":"setStreet","seeList":[],"signature":"setStreet(street)"}],"docTagList":[{"lineNum":5,"name":"author","parameters":["binbin.hou"],"value":"binbin.hou"},{"lineNum":6,"name":"since","parameters":["0.0.1"],"value":"0.0.1"}],"fullName":"com.github.houbb.idoc.test.model.Address","modifiers":["public"],"name":"Address","packageName":"com.github.houbb.idoc.test.model"}
[INFO] ------------------------------------ Finish generate doc
More ways to generate
Of course, you can find that this is just outputting metadata to the console, which is of little significance.
We can customize the implementation of the generated class according to the needs.
For example, in the following way, you can use the built-in MarkdownDocGenerator
output to a markdown file.
<plugin>
<groupId>com.github.houbb</groupId>
<artifactId>idoc-core</artifactId>
<version>0.3.0</version>
<configuration>
<generates>
<generate>com.github.houbb.idoc.ftl.api.generator.MarkdownDocGenerator</generate>
</generates>
</configuration>
<dependencies>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>idoc-ftl</artifactId>
<version>0.3.0</version>
</dependency>
</dependencies>
</plugin>
The effect can refer to:
heaven Document directory
ps: heaven The has been organized by individuals for many years. There are hundreds of categories and handwritten documents are estimated to take a long time.
Original design intention
save time
Java documentation has always been a big issue.
Many projects do not write documentation, and even writing documentation is very painful for developers.
The disadvantages of not writing documents are not much, and the disadvantages of manually writing documents are also obvious:
- It's a waste of time and can make mistakes.
- There is no guarantee of timely updates. The code has changed, but the document needs to be modified simultaneously. Need to force people to maintain this kind of consistency. This is difficult.
Why not swagger-ui
There are several types of java documentation:
- Jdk comes with doc generation. This practice has been used by others before, and others use C#, and it feels painful to see the default documentation of java.
Even if we are java developers, we hate to read the jdk documentation. It looks unattractive and very tired.
- swagger-ui is a document generation tool based on java annotations. Relatively speaking, it is elegant and very powerful.
But there are also disadvantages. Developers need to write jdk original comments + annotations. Too many comments made it painful to write, and most developers later chose to give up.
So the question is coming? What can we do to make developers and document readers as happy as possible?
The doc that comes with jdk is based on the maven plug-in, as is this project.
The differences are as follows:
- As much as possible to ensure that it is consistent with Java's native annotations, so that developers can use them easily.
- The information is as comprehensive as possible, but the document is concise. Let the readers of the document enjoy an experience equivalent to that of a handwritten document.
- Separate the acquisition and generation of information. It is convenient for users to define their own output methods.
Parameter configuration description
In order to achieve more flexible document generation and document metadata generation, the following parameters are provided
Introduction to plugin configuration properties
Attributes | Is it required | illustrate | Defaults | Remark |
---|---|---|---|---|
encoding | no | Project code | UTF-8 | |
includes | no | File information contained in metadata | **\/*.java | Scan all java files by default |
excludes | no | File information excluded by metadata | without | Not excluded by default |
isOverwriteWhenExists | no | Whether to overwrite when the document exists | true | |
isAllInOne | no | Whether to generate a single document for all types of information | true | Command line document generator, this attribute is meaningless. |
generates | no | Document generation class | Command line documentation generation information | You can specify multiple at the same time. The full name of the class. User-defined see com.github.houbb.idoc.api.core.genenrator.IDocGenerator |
generateFilters | no | Document generation filter | without | You can specify multiple at the same time. The full name of the class. User-defined see com.github.houbb.idoc.api.core.filter.IDocGenerateFilter |
targetDir | no | Generate target file directory | without | Customize the folder generated by the specified document |
isAllInOne
Simple documents are recommended to be generated directly in a file.
If it is more complicated, you can set it to false, and it will follow
generates related questions
The default command line document is mainly used for demonstration and information viewing, and has no practical significance.
It is recommended to introduce the idoc-ftl
module and use the MarkdownDocGenerator
generator.
You can specify multiple at the same time.
You can introduce idoc-api
define yourself.
generateFilters suggestions
The actual documentation is mainly concerned with the defined method.
We can filter the package name of DocClass to generate only Service method documents.
If it is based on the previous, you can add @since
@version
and other information filtering.
You can specify multiple at the same time.
You can introduce idoc-api
define yourself.
Custom Filter
You can refer to the idoc-test
module of the current project.
The overall configuration is as follows:
<build>
<plugins>
<plugin>
<groupId>com.github.houbb</groupId>
<artifactId>idoc-core</artifactId>
<version>0.3.0</version>
<configuration>
<isAllInOne>true</isAllInOne>
<generates>
<generate>com.github.houbb.idoc.ftl.api.generator.MarkdownDocGenerator</generate>
</generates>
<generateFilters>
<generateFilter>com.github.houbb.idoc.test.filter.MyGenerateFilter</generateFilter>
</generateFilters>
</configuration>
<dependencies>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>idoc-test</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
Specify the document generator
Specify the Markdown document generator, you can specify multiple at the same time.
<generates>
<generate>com.github.houbb.idoc.ftl.api.generator.MarkdownDocGenerator</generate>
</generates>
Import package
MarkdownDocGenerator needs to introduce the corresponding dependency in the idoc-ftl
Of course, idoc-core
depends on idoc-ftl
default.
Specify the filter of the file generation class
If you do not define your own class generation filter, all class information will be generated.
In general use, we only care about the service method, so the filter implementation of the class is added.
The implementation is as follows:
Introduce idoc-api package
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>idoc-api</artifactId>
<version>${project.version}</version>
</dependency>
Implement IDocGenerateFilter
package com.github.houbb.idoc.test.filter;
import com.github.houbb.idoc.api.core.filter.IDocGenerateFilter;
import com.github.houbb.idoc.api.model.metadata.DocClass;
/**
* 自定义生成过滤器
* @author binbin.hou
* @since 0.0.1
*/
public class MyGenerateFilter implements IDocGenerateFilter {
@Override
public boolean include(DocClass docClass) {
if("QueryUserService".equalsIgnoreCase(docClass.getName())) {
return true;
}
return false;
}
}
Configuration and use in the plug-in
<generateFilters>
<generateFilter>com.github.houbb.idoc.test.filter.MyGenerateFilter</generateFilter>
</generateFilters>
Note that you also need to add dependencies to the jar where you define this filter, otherwise the corresponding class information cannot be found.
<dependencies>
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>idoc-test</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
Class code information
User information
/**
* 用户信息
* @author binbin.hou
* @since 0.0.1
*/
public class User {
/**
* 名称
* @require 是
* @remark 中文名称,请认真填写
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 生日
*/
private Date birthday;
/**
* 地址
*/
private List<Address> addressList;
/**
* 伴侣
*/
private User mate;
//...
}
Tags defined by i-doc
@require
indicates whether the current field is required, when it is used as a method to enter the parameter.
@remark
represents the remark information of the current field.
Method class information
- QueryUserService.java
/**
* 查询用户服务类
* @author binbin.hou
* @since 0.0.1
*/
public interface QueryUserService {
/**
* 根据用户信息查询用户
* @param user 用户信息
* @return 结果
* @since 0.0.2,2019/02/12
*/
public User queryUser(final User user);
}
Execution plugin
mvn com.github.houbb:idoc-core:0.3.0:idoc
- Log information
[INFO] ------------------------------------ Start generate doc
[INFO] 共计 【4】 个文件待处理,请耐心等待。进度如下:
==================================================================================================== 100%
[INFO] Generator doc with docGenerator: com.github.houbb.idoc.ftl.api.generator.MarkdownDocGenerator
[INFO] Markdown 生成文档文件 all in one 路径: /Users/houbinbin/code/_github/idoc/idoc-test/src/main/resources/idoc-gen/idoc-test-全部文档.md
[INFO] ------------------------------------ Finish generate doc
Document information
The current file path log will be printed. For example, what I tested myself is:
/Users/houbinbin/code/_github/idoc/idoc-test/src/main/resources/idoc-gen/idoc-test-all documents.md
Document generation effect
See documentation:
idoc-test-all documents.md
Field type alias support
You can refer to the idoc-test
module of the current project.
Why need
Sometimes the page display type, hoping to be more friendly.
Therefore, the system has built-in alias display, and also supports custom aliases.
Alias of type field
Built-in system
The current version of the system provides common aliases.
See com.github.houbb.idoc.core.util.JavaTypeAliasUtil
type | nickname |
---|---|
java.lang.Float | Floating point |
java.lang.Double | Floating point |
java.util.Date | date |
java.time.LocalDateTime | Date time |
java.util.Currency | currency |
float | Floating point |
java.lang.Integer | Integer |
long | Long integer |
java.math.BigDecimal | number |
java.lang.Character | character |
java.lang.Long | Long integer |
java.lang.Short | Short integer |
java.util.Map | Mapping |
java.time.LocalTime | time |
java.lang.Boolean | Boolean value |
java.math.BigInteger | number |
java.lang.String | String |
java.lang.Byte | byte |
double | Floating point |
byte | byte |
java.util.Collection | gather |
int | Integer |
java.util.List | List |
boolean | Boolean value |
java.time.LocalDate | date |
char | character |
short | Short integer |
void | null |
array | Array |
Custom way
You can specify a custom field alias through typeAlias.
<configuration>
<generateFilters>
<generateFilter>com.github.houbb.idoc.test.filter.MyGenerateFilter</generateFilter>
</generateFilters>
<isAllInOne>true</isAllInOne>
<typeAliases>
<typeAlias>
<key>java.lang.String</key>
<value>String自定义说明</value>
</typeAlias>
</typeAliases>
</configuration>
priority
The user-defined field alias has a higher priority than the system default.
The aliases defined later will directly override the previous aliases.
Test code demo
Object definition
/**
* 别名测试
* @author binbin.hou
* @since 0.0.1
*/
public class TypeAliasSimpleBean {
/**
* 名称
*/
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Test log
The running test log is as follows:
{"comment":"别名测试","docAnnotationList":[],"docFieldList":[{"comment":"名称","name":"name","type":"java.lang.String","typeAlias":"String自定义说明"}],"docMethodList":[{"docMethodParameterList":[],"docMethodReturn":{"fullName":"java.lang.String","name":"String","packageName":"java.lang"},"docTagList":[],"exceptionList":[],"modifiers":["public"],"name":"getName","seeList":[],"signature":"getName()"},{"docMethodParameterList":[{"docAnnotationList":[],"name":"name","type":"java.lang.String","typeAlias":"String自定义说明"}],"docMethodReturn":{},"docTagList":[],"exceptionList":[],"modifiers":["public"],"name":"setName","seeList":[],"signature":"setName(name)"}],"docTagList":[{"lineNum":5,"name":"author","parameters":["binbin.hou"],"value":"binbin.hou"},{"lineNum":6,"name":"since","parameters":["0.0.1"],"value":"0.0.1"}],"fullName":"com.github.houbb.idoc.test.model.TypeAliasSimpleBean","modifiers":["public"],"name":"TypeAliasSimpleBean","packageName":"com.github.houbb.idoc.test.model"}
Among them, typeAlias is the alias of the field type, we can use it to display field information more friendly.
Other thinking
Convenience of customization
The custom way is more convenient to use the xml-based way.
However, it is not so convenient when the number is relatively large. Originally, I considered adding the corresponding configuration attribute interface, but I still used the xml configuration method under the trade-off.
Do you use comment information?
If a field does not specify an alias, do you use comment information instead?
It is recommended to use, the current version will not be processed.
- Why use
Most people are more willing to see explanations than lengthy information.
If it is for a homogeneous system (all java language), you can understand.
If it is for a heterogeneous system (for example, the front desk is PHP), it is not easy to understand.
- Why not deal with
Most of the interfaces are common fields, and the price/performance ratio is not high.
There may be situations where the field does not have some comments, which will cause the complexity of the judgment.
If the user does not want to use an alias
type
modify the template directly, just use the original field 0616d5ac7b7d83 attribute.
Open source address
https://github.com/houbb/idoc
Of course, this project still has a long way to go.
If you like, welcome to fork star~
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。