写在前面
源码 。
在实际工作中,经常有这样的场景,从map中获取值来赋值到某个对象上,这无疑是一个重复的劳动,本文来尝试通过编写一个这样的插件,让插件来帮我们写代码,不管是有1个属性,还是有30个属性,都能在瞬间完成,开始吧!
1:开发
idea已经提供了这样的功能,在generate中生成get,set,tostring等,如下图:
因为我们要做的和这些功能其实是类似,所以,也将菜单放在这里。首先需要创建一个Action:
xml
<action id="map2obj" class="com.dahuyou.action.Map2ObjAction" text="map转对象" description="map转对象插件">
<add-to-group group-id="GenerateGroup" anchor="first"/>
<keyboard-shortcut keymap="$default" first-keystroke="ctrl alt K"/>
</action>
java
public class Map2ObjAction extends AnAction {
@Override
public void actionPerformed(AnActionEvent e) {
Messages.showInfoMessage("点击了", "提示");
}
}
试下效果:
到这里,我们来看下最终要实现的插件希望达到一个什么效果,我们希望是这样的,比如我们有如下的代码:
Map map = fn();
MyObj myObj = new MyObj();
我们要将map中的值设置到myObj中,即最终生成这种代码:
Map map = fn();
MyObj myObj = new MyObj();
myObj.setProp1(map.get("prop1"));
myObj.setProp2(map.get("prop2"));
...
为了实现这个目标,思路是这样子的:
1:用户需要复制Map map,这样我们就可以获取到属性值的数据源信息
2:用户将光标放在MyObj myObj,这样我们就可以获取要设置属性值的目标对象信息
3:动态的生成myObj.setProp1(map.get("prop1"));这种代码到源文件中
首先,来定义接口,如下:
java
/**
* map转obj顶层规范接口,只提供过一个核心的生成代码的方法
*/
public interface IMap2ObjGenerator {
/**
* 唯一的核心方法,具体的操作步骤在抽象子类中以模板方法的方式提供,之后具体子类提供具体实现,完成业务逻辑,
* 这样当我们有很多的子类时,重复的工作就不需要做了,而只需要实现特有的功能就行了
* @param project
* @param dataContext
* @param psiFile
*/
void doGenerate(Project project, DataContext dataContext, PsiFile psiFile);
}
可以看到在接口中我们只有一个核心的方法doGenerate,就是来生成代码的,通过如下的关键步骤来完成工作。
1: 获取用户所在的上下文信息,为后续获取相关信息做准备
2: 获取要设置属性值的目标对象,从中获取其属性信息
3:获取map源对象信息
4:织入set代码
抽象类如下:
java
/**
* 抽象类,提供模板方法
*/
public abstract class AbstractMap2ObjGenerator implements IMap2ObjGenerator {
/**
* 提取属性名称使用 ,如setXyz()则xyz就是属性名称了
*/
protected final String setRegex = "set(\\w+)";
/**
* 模板方法
* @param project
* @param dataContext
* @param psiFile
*/
@Override
public void doGenerate(Project project, DataContext dataContext, PsiFile psiFile) {
// 1: 获取用户所在的上下文信息,为后续获取相关信息做准备
GenerateContext generateContext = generateUserContext(project, dataContext, psiFile);
// 2: 获取要设置属性值的目标对象,从中获取其属性信息
TargetObjInfo targetObjInfo = generateTargetObjInfo(generateContext);
// 3:获取map源对象信息
SourceObjInfo sourceObjInfo = generateSourceObjInfo(generateContext);
// 4:织入set代码
weavingSetCode(targetObjInfo, sourceObjInfo, generateContext);
}
/**
* 织入代码
* @param targetObjInfo
* @param sourceObjInfo
* @param generateContext
*/
protected abstract void weavingSetCode(TargetObjInfo targetObjInfo, SourceObjInfo sourceObjInfo, GenerateContext generateContext);
/**
*
* @param generateContext
* @return
*/
protected abstract SourceObjInfo generateSourceObjInfo(GenerateContext generateContext);
/**
*
* @param generateContext
* @return
*/
protected abstract TargetObjInfo generateTargetObjInfo(GenerateContext generateContext);
/**
*
* @param project
* @param dataContext
* @param psiFile
* @return
*/
protected abstract GenerateContext generateUserContext(Project project, DataContext dataContext, PsiFile psiFile);
}
具体子类为Map2ObjGeneratorImpl
,具体的代码就看源码吧,我觉得最重要的还是这个思路!!!
2:测试
首先创建如下测试类:
java
public class Target {
private String name;
private String age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
接着写测试代码:
java
public class xx {
public static void main(String[] args) {
Map<String, String> sourceMap = new HashMap<>();
sourceMap.put("name", "最激昂萨满");
sourceMap.put("age", "99");
Target target = new Target();
}
}
按照如下步骤测试即可:
3:在idea中安装插件(用起来吧!)
因为我并没有发布到idea的插件市场,所以不能搜索到,但你可以从这里 下载安装包,通过离线安装的方式来使用,如下:
安装完成后,重启idea,如下就是安装成功了:
使用的话就和测试时一样了。
本来想上传到idea市场的,但每次提交直接给我来个服务报错,告诉我hiccup了:
我能咋办???