写在前面
源码 。
在实际工作中,经常有这样的场景,从map中获取值来赋值到某个对象上,这无疑是一个重复的劳动,本文来尝试通过编写一个这样的插件,让插件来帮我们写代码,不管是有1个属性,还是有30个属性,都能在瞬间完成,开始吧!
1:开发
idea已经提供了这样的功能,在generate中生成get,set,tostring等,如下图:
 
 因为我们要做的和这些功能其实是类似,所以,也将菜单放在这里。首先需要创建一个Action:
 
<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>
 
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"));这种代码到源文件中
 
首先,来定义接口,如下:
/**
 * 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代码
 
抽象类如下:
/**
 * 抽象类,提供模板方法
 */
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:测试
首先创建如下测试类:
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;
    }
}
 
接着写测试代码:
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了:
 
 我能咋办???
你安装使用了吗?是的话就点个赞让我知道下吧🙁🙁🙁!!!
写在后面
参考文章列表
idea插件开发之系列 。



















