Recently, the author is doing the reduction of the inventory of the warehouse, and the first consideration is the reduction based on static scanning, and I have tried to use many tools to optimize the inventory, such as PMD, the inspect function that comes with Idea, findbugs, etc. But without exception, either they are too "conservative" and only give scan results, but they can't achieve one-click optimization, or they are directly buggy (here specifically refers to idea2023.)1.5 Professional -inspect function scans the unused declaration in the problems list). For the lazy person, manually clicking a button hundreds of times is no different from going to jail, so he wrote a tool to modify most of the specified optimization points with one click (specifically, using Lombok's @data annotations to replace the explicit getter setter and tostring methods).
The content of this article is mainly divided into three parts, the first part describes the idea of tool implementation in detail, the second part will give a brief introduction to the open source tool j**aparser, and the third part provides detailed instructions for the use of the tool.
When looking through the history, I found that many classes in many engineering repositories are still used to generate getter setters, and if you use Lombok's @data annotations to replace them, it can bring several advantages.
Obviously, it makes it cleaner, reduces the volume, and reduces the duplication of effort that comes with adding new fields in the future.
Readability has been improved, and there is no need to check if there is logic in the getter setter when other colleagues are involved in the development.
Avoid omissions and reduce the risk of making mistakes, because other colleagues' interface data omitted to write the get method, which has increased a lot of communication costs.
Looking back, let's look at the steps we need to write a tool that does a full scan of all classes in the entire project, and replaces the getters and setters with "no special logic" with lombok.
1.Scan the entire project**, which can be a multi-module project.
2.Read the ".j**a" file.
3.Filter out unwanted classes, such as interfaces, classes without fields (most likely as services), annotated declarations, and so on.
4.To remove the getter setter method, you need to determine whether there is any special logic in the get and set methods.
5.Annotate the class with @data and bring in the lombok package.
6.Write the modified content to the j**a file.
The implementation of each step is described below.
Engineering scanning is relatively simple, giving a project path and then calling it recursively, filtering out all of them. j**a file.
private static list scanj**afiles(file file) for (file f : files) if (file.getname().endswith(".j**a")) return result; }
Once you have a list of all the files, you need to process them.
1.Filter out classes with no fields.
2.Filter out classes that already use lombok annotations.
3.Determine whether there is an explicit getter setter (note here that fields of type boolean require special handling).
4.Determine whether the getter setter is a simple return and assignment operation.
5.Delete the getter setter.
6.Add @data annotations.
7.Added introduction of lombok packages.
Here we use the open source tool j**aparser on github to parse, extract, delete and add new content to the class, which will be introduced in the next chapter.
This is a bit simpler and crude, directly using equals to determine the method body, in fact, j**aparser provides a more complete API to analyze semantics.
After cleaning up the **, you need to update the content to the j**a file, and the compilationunit has rewritten the tostring method, which can support directly converting the ** to the form of a string.
J**Aparser is an open-source J**a source analysis tool that provides a series of simple APIs toParse, modify, and generatej**a **
For example, we can use j**aparser to easily do the following:
1.Analyze elements such as classes, methods, and fields in **, and extract the inheritance relationship of the class, the parameters of the method, and the return type.
2.Change the source code, such as renaming a method, modifying a method body, adding or removing a line, and so on.
3.You can use it to generate fragments, such as creating new classes, methods, or fields, or to generate documents.
In the previous chapter, we used the data extraction and source code replacement functions. Here is a link to j**aparser:
Official website: github: wiki:wiki.git j**adoc:The main components of j**aparser are the following components:
1.lexer: The lexer is used to read the source text and break it down into a series of tokens, such as keywords, identifiers, literals, operators, etc. This is the first step in the parsing process.
Usually we don't need to call it explicitly, j**aparser hides the specific details of the implementation inside, and the caller only needs to use the open API to complete the source code to AST conversion. For details, you can flip through comgithub.j**aparser.generatedj**aparser
2.Parser: The parser receives tokens generated by the lexer and combines them into various syntactic structures, such as expressions, statements, class definitions, etc., according to the syntax rules of the J**A language. This process builds an Abstract Syntax Tree (AST).
com.github.j**aparser.j**aparser is the most commonly used class to trigger the parsing process and generate an AST, in the previous section, the source file was parsed into a compilationunit using staticj**aparser, and the j**aparser was used inside the parse method to complete this parsing process.
3.AST (Abstract Syntax Tree): AST is the core data structure of j**aparser, which represents the structure of the source in a hierarchical way. An AST consists of a series of nodes, each representing an element in the source, such as a class, method, field, expression, and so on. Each node contains information about the element, such as name, type, modifier, and so on.
AST is the basis for subsequent operations (e.g., traversal, analysis, modification) and is the class that consumers operate on the most. The com. used in the previous sectiongithub.j**aparser.ast.CompilationUnit is a very important class that represents the root node of the ja source file and is an abstract representation of this structure, containing the structure of the entire file, for example:
Package Declaration
Imports
Type declarations, which may be classes, interfaces, enumerations, or annotations.
Comments
Any top-level annotation.
By manipulating the public methods provided by the compilationunit, you can access and modify the elements in the file. Includes:
Get and set package declarations.
Get and add import declarations.
Get and add type declarations.
Get and add comments.
Use the visitor pattern to traverse the nodes in the AST.
4.Visitors: As the name suggests, this is a component designed with visitor mode in mind that can be used to traverse and manipulate AST. Developers can write custom visitors, access specific types of nodes by traversing the AST, and perform tasks such as analysis, refactoring, and generation.
com.github.j**aparser.ast.visitor.genericvisitor and comgithub.j**aparser.ast.visitor.The two accessors provide default implementations, and if you need custom accessors, you can inherit them to implement your own business logic.
5.Printer: This is also easy to understand, as Printer is used to convert AST back to a string representation of the Ja source. It can print the modified AST back to the original source file, or print the AST as a formatted string. The Tostring method rewritten by the CompilationUnit mentioned at the end of the previous chapter actually uses the printer to convert AST to source strings.
Some of the above components are the core and commonly used parts of j**aparser, of course, j**aparser also provides some convenient tools and usage, which the author has not touched, and readers in need can flip through the documents by themselves.
The JAR package and source code mentioned in the first chapter have been uploaded to the private server, and can be run directly through the m**en plugin.
com.jd.omni.opdd lombok-replace 0.0.1-snapshot
org.codehaus.mojo exec-m**en-plugin 3.0.0 j**a com.jd.omni.opdd.tools.lombok.lombokconverter ../../pop-jingme-customs
The argument node in the plugin needs to be replaced with the path of the project, which can be an absolute path or a relative path.
Execute mvn exec:j**a
It can be seen in the console:
After the processing is completed with the tool, be sure to check whether there are compilation errors in the build, although the more stringent verification is done when deleting the operation, but some special variable names may not be taken into account, and this part of the problem can be checked by compilation.
Also, for modules that don't reference lombok, you need to manually add dependencies.
* Reconstruction should be like a scalpel, fast, accurate, ruthless, as the so-called gentleman is not different, good and fake in things. This article mainly plays a role in throwing bricks and jade, focusing on the introduction of j**aparser, the author wrote this gadget is very simple, and I have also written b-paas one-click generation matrixJSON, one-click generation of i18n files according to the error code definition, most of them are not difficult.
If you think about divergently, you can do some interesting things by combining j**apaser with the open APIs provided by other platforms, such as combining the APIs of jsf, ump, and pfinder to achieve method cleanup without callers.
In addition to **refactoring, you can also do some **visualization tools after getting the syntax tree, refer to the previously released "**visualization" written by Xie Xiao.
Author: Jingdong Retail Tan Lei.
*:JD Cloud Developer Community**Please indicate**.