I wrote an IDEA open source plug-in, vo2dto one click to generate object transformation

Posted by Vorotaev on Fri, 31 Dec 2021 07:08:01 +0100

Header explosion, po2vo, vo2do, do2dto, a bunch of object attributes, take them out and stuff them in. If it were not for the layered anti-corrosion under the DDD architecture, I really want to connect it.

That's BeanUtils Copyproperties , in fact, there are not only this method but also 12 similar methods for object conversion, but overall, the final effect of , mapstructure , generating x.set(y.get) code during compilation is the best. The overall pressure test data are as follows:

  • BeanUtils.copyProperties , is the most common tool class in your code, but as long as you don't mistake it for the one under Apache package, but use the one provided by Spring, it won't have much impact on performance.
  • However, if the performance is better, it can replace manual get and set, or MapStruct is better, because it itself generates get and set code during compilation, just like we write get and set.
  • Other component packages are mainly implemented based on AOP, ASM and CGlib, so there will be corresponding performance loss.

how? Do you write a MapStruct for every operation that converts object attributes? It's not appropriate. Some methods are very simple. You can write code and get it done. The problem is to write lazily. It's easy to make mistakes when there are more than one. Don't mention BeanUtils Sometimes copyproperties are identified as having performance problems, and the addition and reduction of properties can not be seen from the coding

So {I want to write an IDEA Plugin to solve this problem. The purpose is to define two objects whose attributes I need to convert through the development ability of the IDEA plug-in, automatically generate the conversion codes of the two objects, and weave them into my object location.

Design a plug-in

I think like this: in the IDEA development engineering code, copy the first object and attribute between the two objects to be converted, and then position the cursor on the conversion object. Next, I provide it with a button or shortcut key to generate all the conversion codes at one click. This solves the problem of handwriting. The effects are 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
 Copy code

Source code acquisition: github.com/fuzhengwei/... - welcome to submit issue and PR for joint maintenance

The IDEA plug-in project is mainly divided into four areas:

  • action: provide a menu bar form. In the plug-in, we configure this menu bar under "Generate", that is, where you usually Generate get, set and constructor methods.
  • Application: the application layer defines the interface, which defines a method interface for generating code and weaving it into the anchor point.
  • domian: the domain layer is dedicated to the generation and weaving of code. This layer obtains the anchor position in the code, copies the clipboard information, parses the application context, get and set in the class, and finally weaves the generated code into the anchor.
  • infrastructure: a tool class is provided in the foundation layer, which is used to obtain shear plate information and anchor position judgment.

2. Weaving code interface

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

public interface IGenerateVo2Dto {

    void doGenerate(Project project, DataContext dataContext);

}
Copy code
  • Defining an interface is actually a very important step, because this step defines the generation standard, and all generation actions should be initiated from this interface. Learning the source code is the same. You need to find a core entry point in order to better start learning

3. Define template method

Because the operation of generating code and weaving it into the anchor position is actually a set of process operations, because it is necessary in this process; Get the context information (that is, the project object), extract the set method set for the class at the current anchor location, and then read the information on the Ctrl+C clipboard to extract the get method set. Step 4: combine set and get and weave the code into the anchor location. 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 their responsibilities.
  • At the same time, because of the definition of the template, the whole set of standard processes is defined. It is easier to execute the code under the process specification and supplement the logic iteration function later.

4. Code weaving anchor

Before the code is woven into the anchor point, the methods defined in the template class need to implement the interface for processing, focusing on:

  1. Via commondatakeys EDITOR. getData(dataContext),CommonDataKeys.PSI_ELEMENT.getData(dataContext) encapsulates the context information of the GenerateContext object, that is, the objects of some classes, anchor locations and document editing.
  2. Obtain the Class class information corresponding to the cursor position through PsiClass. In PsiClass Getmethods () reads the object method, filters out the set method and encapsulates it in the collection.
  3. Through toolkit getDefaultToolkit(). Getsystemclipboard () gets the clipboard information, that is, when you generate {x.set(y.get) for the object at the anchor position, copy the Y object, and start to extract the get method, which is also encapsulated in the set.
  4. Then, the final part is the assembly and weaving of the code. This part of our code 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();
    // Get space position length
    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);
            });
        }
    });
}
Copy code
  • The process action of weaving code is mainly to traverse the set method set and pass the corresponding x.set(y.get) through document Insertstring to the specific location and code.
  • Finally, the weaving of all generated code methods is completed, that is, the whole} x.set(y.get) process is completed.

5. Configure menu entry

plugin.xml

<actions>
    <!-- Add your actions here -->
    <action id="Vo2DtoGenerateAction" class="cn.bugstack.guide.idea.plugin.action.Vo2DtoGenerateAction"
            text="Vo2Dto - Little brother Fu" 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>
Copy code
  • This time, we add a shortcut key to the operation of generating} x.set(y.get) code, which can make it more convenient for us to operate.

Installation and use verification

Next, you can convert the object of So Easy as follows:

  1. Copy the object you need to be converted, because after copying, the plug-in can obtain the clipboard information and extract the get method collection.
  2. Define the mouse to the object that needs to convert the setting value, right-click the mouse and select "Generate - > Vo2Dto - little brother Fu"

1. Copy object

2. Generate object

3. Final effect

  • Finally, you can see that you have converted all your objects and automatically generated code. Isn't it very fragrant.
  • If you directly use the shortcut keys Ctrl + Shift + K , it can also be generated automatically.

Take it and use it. You'd better give me some more suggestions. You are very welcome to submit issue and PR!

Topics: Java IntelliJ IDEA Back-end Programmer intellij-idea