Write document
As a developer, everyone has to write code.
At work, almost every developer has to write documents.
Because the work is the cooperation between people, the product needs to write requirements documents, the development needs to write detailed design documents and interface documents.
However, as a lazy person, one of the most annoying things is to write documents.
What annoys me most about writing documents is that the code comments need to be changed again, and then the documents need to be changed again.
All repeated work is the biggest waste of our valuable fishing time.
So, I often think, can you just write it once?
i-doc project introduction
idoc Generate project documents for java projects.
Generate introduction documents as much as possible based on native java annotations. Users can customize their own templates and generate documents they need.
Implementation principle: Based on maven plug-in, similar to javadoc. Can be more flexible, allowing users to customize.
characteristic
(1) Generate metadata containing most of the information based on the maven project
(2) By default, markdown is supported to simplify document generation, and user-defined templates are supported
(3) Support user-defined document generator
(4) Supports user-defined class filters for generated documents
(5) Add field type alias to support user customization
quick get start
need
jdk1.8+
maven 3.x+
maven introduction
Use maven to introduce the current idoc plug-in.
<build> <plugins> <plugin> <groupId>com.github.houbb</groupId> <artifactId>idoc-core</artifactId> <version>0.3.0</version> </plugin> </plugins> </build>
Creation of test object
To demonstrate the document, we created an Address object.
package com.github.houbb.idoc.test.model; /** * address * @author binbin.hou * @since 0.0.1 */ public class Address { /** * city */ private String country; /** * street */ 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; } }
Execute plug-in
mvn com.github.houbb:idoc-core:0.3.0:idoc
Command line log information
[INFO] ------------------------------------ Start generate doc [INFO] A total of [1] files are pending. Please wait patiently. The progress is as follows: ==================================================================================================== 100% [INFO] Generator doc with docGenerator: com.github.houbb.idoc.core.api.generator.ConsoleDocGenerator [INFO] ------------------------------------ The document information is as follows: [Class name] com.github.houbb.idoc.test.model.Address [Class information] {"comment":"address","docAnnotationList":[],"docFieldList":[{"comment":"city","name":"country","type":"java.lang.String"},{"comment":"street","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 generation methods
Of course, you can find that the metadata is only output to the console, which is of little significance.
We can customize the implementation to generate classes according to our needs.
For example, in the following way, you can use the built-in MarkdownDocGenerator to output to the 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>
Refer to:
ps: heaven The project is a toolkit that individuals have sorted out for many years, hundreds of classes, and handwritten documents. It is estimated that it will take a long time.
Original design intention
Saving time
Java documentation has always been a big problem.
Many projects do not write documents. Even if they do, it is very painful for developers.
The disadvantages of not writing documents are not many, and the disadvantages of writing documents manually are also obvious:
-
It's a waste of time and can make mistakes.
-
Timely updates cannot be guaranteed. The code has changed, but the document needs to be modified synchronously. People need to be forced to maintain this consistency. It's very hard.
Why not swagger UI
There are several types of java documents:
- jdk built-in doc generation. This practice has been used by others before. Others use C #, and it's painful to see the default document of java.
Even we java developers hate reading jdk documents. It looks ugly and tired.
- Swagger UI is a document generation tool based on java annotations. Relatively elegant and powerful.
But there are also shortcomings. Developers should write jdk original comments + comments. Too many comments made it painful to write, and most developers chose to give up later.
So here comes the question...? What can we do to make developers and document readers happy to accept it as much as possible?
The doc provided with jdk is based on maven plug-in, and so is this project.
The differences are as follows:
-
Ensure the consistency with Java Native annotations as much as possible, so that developers can use them easily.
-
The information is as comprehensive as possible, but the documents are concise. Let document readers enjoy the experience equivalent to handwritten documents.
-
Distinguish the acquisition and generation of information. It is convenient for users to define their own output mode.
Parameter configuration description
In order to more flexibly generate documents and document metadata, the following parameters are provided
Introduction to plug-in configuration properties
attribute | Required | explain | Default value | remarks |
---|---|---|---|---|
encoding | no | Item code | UTF-8 | |
includes | no | File information contained in metadata | **\/*.java | All java files are scanned by default |
excludes | no | File information excluded by metadata | nothing | Not excluded by default |
isOverwriteWhenExists | no | Overwrite when document exists | true | |
isAllInOne | no | Whether all class information generates a single document | true | Command line document generator, this property is meaningless. |
generates | no | Document generation class | Command line document generation information | You can specify multiple at the same time. Full name of the class. See com.github.houbb.idoc.api.core.genenrator.IDocGenerator for user customization |
generateFilters | no | Document generation class filter | nothing | You can specify multiple at the same time. Full name of the class. See com.github.houbb.idoc.api.core.filter.IDocGenerateFilter for user customization |
targetDir | no | Generate target file directory | nothing | Custom specifies the folder where the document is generated |
isAllInOne
Simple documents are recommended to be generated directly in a file.
If it is complex, it can be set to false, and it will be set according to
Issues related to generators
The default command line document is mainly used for demonstration and information viewing, which has no practical significance.
It is recommended to introduce IDoc FTL module and use MarkdownDocGenerator generator.
You can specify multiple at the same time.
IDoc API can be introduced for self definition.
generateFilters recommendations
The actual document is mainly concerned with the defined method.
We can filter the package name of DocClass and only generate 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.
IDoc API can be introduced for self definition.
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 document builder
Specifies that you can use the Markdown document generator to specify multiple documents at the same time.
<generates> <generate>com.github.houbb.idoc.ftl.api.generator.MarkdownDocGenerator</generate> </generates>
Import package
The MarkdownDocGenerator needs to introduce corresponding dependencies in the IDoc FTL module.
Of course, IDoc core relies on IDoc FTL by default.
Specifies the filter for the file generation class
If you do not define your own class generation filter, all class information will be generated.
In general, we only care about the service method, so we add the filter implementation of the class.
The implementation is as follows:
Introducing 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; /** * Custom build filter * @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 plug-in
<generateFilters> <generateFilter>com.github.houbb.idoc.test.filter.MyGenerateFilter</generateFilter> </generateFilters>
Note that you also need to add dependencies to the jar that defines 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
/** * User information * @author binbin.hou * @since 0.0.1 */ public class User { /** * name * @require yes * @remark Chinese name, please fill in carefully */ private String name; /** * Age */ private int age; /** * birthday */ private Date birthday; /** * address */ private List<Address> addressList; /** * partner */ private User mate; //... }
i-doc defined tags
@require indicates whether the current field is required. When entering a parameter as a method.
@remark indicates the comment information of the current field.
Method class information
- QueryUserService.java
/** * Query user service class * @author binbin.hou * @since 0.0.1 */ public interface QueryUserService { /** * Query users according to user information * @param user User information * @return result * @since 0.0.2,2019/02/12 */ public User queryUser(final User user); }
Execute plug-in
mvn com.github.houbb:idoc-core:0.3.0:idoc
- log information
[INFO] ------------------------------------ Start generate doc [INFO] There are [4] documents to be processed in total. Please wait patiently. The progress is as follows: ==================================================================================================== 100% [INFO] Generator doc with docGenerator: com.github.houbb.idoc.ftl.api.generator.MarkdownDocGenerator [INFO] Markdown Generate document file all in one route: /Users/houbinbin/code/_github/idoc/idoc-test/src/main/resources/idoc-gen/idoc-test-All documents.md [INFO] ------------------------------------ Finish generate doc
document information
The current file path log will be printed. For example, my own test is:
/Users/houbinbin/code/_ GitHub / IDoc / IDoc test / SRC / main / resources / IDoc Gen / IDoc test - all documents.md
Document generation effect
See documentation:
Field type alias support
You can refer to the IDoc test module of the current project.
Why
Sometimes the page display type, I hope it is more friendly.
Therefore, the system has built-in alias display and supports user-defined aliases.
Alias for type field
Built in system
The current version of the system provides common aliases.
See com.github.houbb.idoc.core.util.JavaTypeAliasUtil for details
type | Nickname |
---|---|
java.lang.Float | float |
java.lang.Double | float |
java.util.Date | date |
java.time.LocalDateTime | Date time |
java.util.Currency | currency |
float | float |
java.lang.Integer | integer |
long | Long integer |
java.math.BigDecimal | number |
java.lang.Character | character |
java.lang.Long | Long integer |
java.lang.Short | Short |
java.util.Map | mapping |
java.time.LocalTime | time |
java.lang.Boolean | Boolean value |
java.math.BigInteger | number |
java.lang.String | character string |
java.lang.Byte | byte |
double | float |
byte | byte |
java.util.Collection | aggregate |
int | integer |
java.util.List | list |
boolean | Boolean value |
java.time.LocalDate | date |
char | character |
short | Short |
void | empty |
array | array |
Custom mode
You can specify custom field nicknames 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 Custom description</value> </typeAlias> </typeAliases> </configuration>
priority
The user-defined field alias has higher priority than the system default.
The alias defined later will directly overwrite the previous alias.
Test code demonstration
Object definition
/** * Alias test * @author binbin.hou * @since 0.0.1 */ public class TypeAliasSimpleBean { /** * name */ 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":"Alias test","docAnnotationList":[],"docFieldList":[{"comment":"name","name":"name","type":"java.lang.String","typeAlias":"String Custom description"}],"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 Custom description"}],"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"}
typeAlias is the alias of field type, which can be used to display field information more friendly.
Other thoughts
Convenience of customization
It is more convenient to customize the method based on xml.
However, it is not so convenient when there are a large number. Originally, it was considered to add the corresponding configuration attribute interface. Under the balance, the xml configuration method was used.
Use comment information?
If an alias is not specified for a field, do you want to use the comment information instead?
It is recommended to use. The current version will not be processed.
- Why
Most people prefer to see explanations rather than lengthy class information.
If it is for isomorphic systems (all java language), it can be understood.
If it is aimed at heterogeneous systems (such as PHP in the foreground), it is not easy to understand.
- Why not deal with it
Most interfaces are common fields with low cost performance.
There may be no comment s in the field, which will lead to the complexity of judgment.
If the user does not want to use an alias
You can directly modify the template and use the original field type attribute.
Open source address
Of course, this project still has a long way to go.
If you like, welcome fork star~