作者:小傅哥 博客:https://bugstack.cn
>沉淀、分享、成长,让自己和他人都能有所收获!😄
头炸,po2vo
、vo2do
、do2dto
,一堆对象属性,取出来塞进来。要不是为了 DDD 架构下的各个分层防腐,真想一竿子怼下去。
那上 BeanUtils.copyProperties
呀,其实对象转换不只这个方法,还有同类的12种手段,但综合来看还是 MapStruct
在编译期生成x.set(y.get)代码的最终效果最好,整体压测数据如下:
BeanUtils.copyProperties
是大家代码里最常出现的工具类,但只要你不把它用错成 Apache
包下的,而是使用 Spring 提供的,就基本还不会对性能造成多大影响。get、set
的,还是 MapStruct
更好用,因为它本身就是在编译期生成get、set
代码,和我们写get、set
一样。AOP
、ASM
、CGlib
,的技术手段实现的,所以也会有相应的性能损耗。咋办? 给每一个转换对象属性的操作都写一个 MapStruct
吗?也不合适呀,有些就是方法中很简单的操作一下,写写代码就能搞定,问题就是懒的写,一多了还容易写错。别提 BeanUtils.copyProperties 有时候确定有性能问题,从编码上还看不出来属性的添加和减少
所以 我要写个 IDEA Plugin 解决这个问题,目的就一个,通过 IDEA 插件开发能力,定义到我需要转换属性的2个对象,把2个对象的转换代码自动生成出来,并织入到我的对象定位位置上。
我是这么思考的:在 IDEA 开发工程代码中,在需要转换的2个对象间,复制第一个对象和属性,再把光标定位到转换对象上,接下来我给它提供个按钮或者快捷键,一点就把所有转换代码生成出来,这样不就解决了需要手写的问题了吗,效果如下:
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
源码获取:https://github.com/fuzhengwei/vo2dto - 欢迎提交 issue、PR 共同维护
在此 IDEA 插件工程中,主要分为4块区域:
Generate
下,也就是通常你生成 get、set、constructor 方法的地方。cn.bugstack.guide.idea.plugin.application.IGenerateVo2Dto
public interface IGenerateVo2Dto {
void doGenerate(Project project, DataContext dataContext);
}
因为生成代码并织入锚点位置的操作,整个来看其实也是一套流程操作,因为在这个过程需要;获取上下文信息(也就是工程对象)、给当前锚点位置的类提取 set 方法集合、之后在给Ctrl+C
剪切板上的信息读取出来提取 get 方法集合,第四步把set、get进行组合并织入代码到锚点位置。整体过程如下:
关于代码织入锚点前,我们在模板类中定义的方法,需要实现接口进行处理,重点包括:
CommonDataKeys.EDITOR.getData(dataContext)
、CommonDataKeys.PSI_ELEMENT.getData(dataContext)
封装 GenerateContext 对象上下文信息,也就是一些类、锚点位置、文档编辑的对象。psiClass.getMethods()
读取对象方法,把 set 方法过滤出来,封装到集合中。Toolkit.getDefaultToolkit().getSystemClipboard()
获取剪切板信息,也就是你在锚点位置给对象生成 x.set(y.get)
时,复制的 Y y 对象,并开始提取 get 方法,同样封装到集合中。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);
});
}
});
}
x.set(y.get)
通过 document.insertString
到具体的位置和代码。x.set(y.get)
的过程。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>
x.set(y.get)
代码的操作加个快捷键,可以让我们更加方便的进行操作。接下来你就可以 So Easy 的转换对象了,操作如下:
Generate
-> Vo2Dto - 小傅哥
Ctrl + Shift + K
也是可以自动生成的。拿去用用吧,最好再给提一些建议,提交issue、提交PR,都非常的欢迎!</string>
|