3
头图

The headache of object conversion

Head bomb, po2vo , vo2do , do2dto , a bunch of object attributes, take them out and stuff them in. If it weren't for the layered anti-corrosion under the DDD architecture, really wanted to go down .

That the BeanUtils.copyProperties Yeah, in fact, not only this object conversion method, there are 12 kinds of similar means, but the whole is still MapStruct generate x.set (y.get) code at compile the best final results, the overall pressure measurement data as follows :

  • BeanUtils.copyProperties is the most common tool category in your code, but as long as you don't use it Apache package, but use Spring provided, it will basically not have much impact on performance.
  • But if the performance is better, it can replace the manual get、set , or MapStruct better, because it itself generates the get、set code at compile time, just like we write get、set
  • Some other component packages are mainly based on AOP , ASM , CGlib , so there will be corresponding performance losses.

? to operate each object attributes are converted to write a MapStruct it? It’s not appropriate. Some are just simple operations in the method, and you can get it done by writing code. The problem is lazy writing, and it is easy to make mistakes when there are too many. Don't mention BeanUtils.copyProperties. Sometimes it is determined that there is a performance problem, and the addition and reduction of attributes cannot be seen from the coding

So I want to write an IDEA Plugin to solve this problem, the purpose is one, through IDEA plug-in development capabilities, defined to the two objects I need to convert attributes, the conversion code of the two objects is automatically generated, and weave it into me The object positioning position.

Design a plug-in

I think this way: In the IDEA development project code, between the two objects that need to be converted, copy the first object and attributes, and then position the cursor on the converted object, and then I will provide it with a button or shortcut key , All the conversion codes are generated at one point, so that the problem of handwriting is solved, the effect is as follows:

1. Engineering structure

vo2dto
├── .gradle
└── src
    ├── main
    │   └── java
    │       └── cn.bugstack.guide.idea.plugin 
    │           ├── action
    │           │    └── Vo2DtoGenerateAction.java     
    │           ├── application
    │           │    └── IGenerateVo2Dto.java      
    │           ├── domain
    │           │    ├── model
    │           │    │    ├── GenerateContext.java     
    │           │    │    ├── GetObjConfigDO.java      
    │           │    │    └── SetObjConfigDO.java       
    │           │    └── service   
    │           │         ├── impl     
    │           │         │    └── GenerateVo2DtoImpl.java    
    │           │         └── AbstractGenerateVo2Dto.java      
    │           └── infrastructure   
    │                └── Utils.java    
    ├── resources
    │   └── META-INF
    │       └── plugin.xml 
    ├── build.gradle  
    └── gradle.properties

Source obtain : https://github.com/fuzhengwei/vo2dto - welcomes the submission issue, PR jointly safeguard

In this IDEA plug-in project, it is mainly divided into 4 areas:

  • action: Provide the menu bar form. In the plug-in, we configure this menu bar Generate , which is where you usually generate get, set, and constructor methods.
  • application: The application layer defines the interface, where a method interface for generating code and weaving into the anchor point is defined.
  • domian: The domain layer specializes in code generation and weaving actions. This layer obtains the anchor point position of the code, copies the clipboard information, the application context, the analysis of the get and set in the class, and finally weaves the generated code Operations after reaching the anchor point.
  • Infrastructure: Provides tool classes at the base layer for operations such as obtaining clipboard information and determining the position of anchor points.

2. Weaving code interface

cn.bugstack.guide.idea.plugin.application.IGenerateVo2Dto

public interface IGenerateVo2Dto {

    void doGenerate(Project project, DataContext dataContext);

}
  • Defining the interface is actually a very important step, because this step defines the generated standard, and all generation actions must be initiated from this interface. learning source code is the same, you have to find a core entry point, in order to better start learning

3. Define the template method

Because the operation of generating code and woven into the anchor point position is actually a set of process operations as a whole, because it is required in this process; obtaining context information (that is, engineering object), extracting the set method set for the class of the current anchor point position, After Ctrl+C clipboard to extract the get method set, the fourth step is to combine the set and get and weave the code into the anchor point. The overall process is as follows:

  • Then after using the template method, it is very easy to split the pieces of code written in a class according to responsibilities.
  • At the same time, because of the definition of the template, the entire set of standard processes is defined. It is easier to execute the code under the process specification, and then add the logical iteration function later.

4. Code weaving into anchors

Regarding the method we define in the template class before the code is weaved into the anchor point, the interface needs to be implemented for processing, and the key points include:

  1. Through CommonDataKeys.EDITOR.getData(dataContext) , CommonDataKeys.PSI_ELEMENT.getData(dataContext) encapsulate the GenerateContext object context information, that is, some classes, anchor positions, and document editing objects.
  2. Obtain the Class information corresponding to the cursor position through psiClass.getMethods() read the object method through 061c41e8512cd9, filter out the set method, and encapsulate it into the collection.
  3. Obtain the clipboard information through Toolkit.getDefaultToolkit().getSystemClipboard() , that is, when you generate x.set(y.get) for the object at the anchor point, copy the Y y object and start extracting the get method, which is also encapsulated in the collection.
  4. Then the final part is the assembly and weaving action of the code. Our code for this part is as follows;

cn.bugstack.guide.idea.plugin.domain.service.impl.GenerateVo2DtoImpl

@Override
protected void weavingSetGetCode(GenerateContext generateContext, SetObjConfigDO setObjConfigDO, GetObjConfigDO getObjConfigDO) {
    Application application = ApplicationManager.getApplication();
    // 获取空格位置长度
    int distance = Utils.getWordStartOffset(generateContext.getEditorText(), generateContext.getOffset()) - generateContext.getStartOffset();
    application.runWriteAction(() -> {
        StringBuilder blankSpace = new StringBuilder();
        for (int i = 0; i < distance; i++) {
            blankSpace.append(" ");
        }
        int lineNumberCurrent = generateContext.getDocument().getLineNumber(generateContext.getOffset()) + 1;
        List<String> setMtdList = setObjConfigDO.getParamList();
        for (String param : setMtdList) {
            int lineStartOffset = generateContext.getDocument().getLineStartOffset(lineNumberCurrent++);
            
            WriteCommandAction.runWriteCommandAction(generateContext.getProject(), () -> {
                generateContext.getDocument().insertString(lineStartOffset, blankSpace + setObjConfigDO.getClazzParamName() + "." + setObjConfigDO.getParamMtdMap().get(param) + "(" + (null == getObjConfigDO.getParamMtdMap().get(param) ? "" : getObjConfigDO.getClazzParam() + "." + getObjConfigDO.getParamMtdMap().get(param) + "()") + ");\n");
                generateContext.getEditor().getCaretModel().moveToOffset(lineStartOffset + 2);
                generateContext.getEditor().getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);
            });
        }
    });
}
  • Weaving process operation code, the main method of collection is set to traverse, the corresponding x.set(y.get) by document.insertString to a specific location and code.
  • In the end, all the generated code methods are woven, and the whole process of x.set(y.get)

5. Configuration menu entry

plugin.xml

<actions>
    <!-- Add your actions here -->
    <action id="Vo2DtoGenerateAction" class="cn.bugstack.guide.idea.plugin.action.Vo2DtoGenerateAction"
            text="Vo2Dto - 小傅哥" description="Vo2Dto generate util" icon="/icons/logo.png">
        <add-to-group group-id="GenerateGroup" anchor="last"/>
        <keyboard-shortcut keymap="$default" first-keystroke="ctrl shift K"/>
    </action>
</actions>
  • This time we x.set(y.get) , which allows us to operate more conveniently.

Installation and use verification

Then you can convert the object of So Easy, the operation is as follows:

  1. Copy the object you need to be converted, because after copying, the clipboard information can be obtained by the plug-in, and the get method set can also be extracted.
  2. Define the mouse to the object that needs to convert the setting value, then right-click the mouse and select Generate -> Vo2Dto-Xiao Fu Ge

1. Copy objects

2. Generate objects

3. Final effect

  • In the end, you can see that all your objects have been converted, and the code has been automatically generated. Is it very fragrant?
  • If you directly use the shortcut key Ctrl + Shift + K can also be automatically generated.

Let's use it, it's best to give some suggestions, submit an issue, submit a PR, all are very welcome!


小傅哥
4.7k 声望28.4k 粉丝

CodeGuide | 程序员编码指南 - 原创文章、案例源码、资料书籍、简历模版等下载。