likes
comments
collection
share

idea插件,如何通过psi文件追加代码背景 为了提高插件的实用性,我们考虑加入代码的追加的功能,简单来讲,就是通过插件

作者站长头像
站长
· 阅读数 50

背景

为了提高插件的实用性,我们考虑加入代码的追加的功能,简单来讲,就是通过插件,去生成controller和service的层级代码,避免我们为了创建层级去来回切换,同时也是强制保持代码的规范。

实践

我们考虑是在右键菜单中添加一个组件,进行控制 大概是这个效果 idea插件,如何通过psi文件追加代码背景 为了提高插件的实用性,我们考虑加入代码的追加的功能,简单来讲,就是通过插件 首先需要继承AnAction类,重写actionPerformed方法,控件触发的时候,会执行这个方法

public class GenerateMethodAction extends AnAction {

    private final IProjectGenerator<MethodConfigVO> methodGenerator = new MethodGeneratorImpl();

    @Override
    public void actionPerformed(AnActionEvent event) {

        Project project = event.getProject();
        if (project == null) {
            return;
        }

        PropertiesComponent instance = PropertiesComponent.getInstance(project);
        String projectStruct = instance.getValue(CommonConstants.PROJECT_STRUCT_KEY);
        MethodConfigVO methodConfigVO = JSONUtil.toBean(projectStruct, MethodConfigVO.class);
        // 定义对话框,当前组件执行的时候进行显示
        GenerateMethodDialog dialog = new GenerateMethodDialog(project)
    }
}

然后就是获取psi文件,并追加代码。

        Project project = event.getProject();
        if (project == null) {
            return;
        }
        // 获取LocalFileSystem实例
        LocalFileSystem localFileSystem = LocalFileSystem.getInstance();

        // 将文件系统路径转换为VirtualFile
        VirtualFile virtualFile = localFileSystem.findFileByPath(outputPath);

我们需要获取当前的项目和本地的文件系统,查找对应的路径的VirtualFile,VirtualFile是idea基于硬盘上的文件进行映射的,简单理解就是本地文件的一个引用。由于idea会不停的刷新VirtualFile,所以我们还需要调用virtualFile.isValid()方法,判断文件是否已经失效。

            // 获取PsiElementFactory实例
            PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
            // 获取PsiManager实例
            PsiManager psiManager = PsiManager.getInstance(project);
            // 获取导包列表
            List<PsiImportStatement> psiImportStatements = buildImportStatement(factory, methodTemplate);

            // 从VirtualFile获取PsiFile
            PsiFile psiFile = psiManager.findFile(virtualFile);

然后在获取java的psi元素,用来获取引入的包列表,然后通过virtualFile获取到对应的psi文件,psi就是idea专门提供的用来简化解析代码文件操作的一个类。

            if (psiFile instanceof PsiJavaFile) {
                PsiClass psiClass = PsiTreeUtil.findChildOfType(psiFile, PsiClass.class, false);
                if (psiClass != null) {
                    // 添加方法
                    boolean isInterface = PsiUtil.isJavaInterfaceFile(psiFile);
                    PsiMethod newMethod = buildPsiMethod(factory, psiClass, methodTemplate, isInterface);
                    psiClass.add(newMethod);
                    // 格式化新插入的代码
                    CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(project);
                    codeStyleManager.reformat(newMethod);
                    // 导包
                    PsiJavaFile psiJavaFile = (PsiJavaFile) psiClass.getContainingFile();
                    PsiImportList importList = psiJavaFile.getImportList();
                    List<String> existImports = Arrays.stream(importList.getImportStatements()).map(PsiImportStatement::getQualifiedName).collect(Collectors.toList());
                    for (PsiImportStatement importStatement : psiImportStatements) {
                        if (!existImports.contains(importStatement.getQualifiedName())) {
                            importList.add(importStatement);
                        }
                    }
                }
            }

获取对应的psiclass文件,构建新的方法,并添加到PsiClass中

    private static PsiMethod buildPsiMethod(PsiElementFactory factory, PsiClass psiClass, MethodDTO methodTemplate, boolean isInterface) {
        PsiType returnType = PsiType.VOID;
        if (Objects.nonNull(methodTemplate.getReturnTypeClass())) {
            returnType = factory.createTypeFromText(methodTemplate.getReturnType(), null);
        }
        // 创建新方法
        PsiMethod newMethod = factory.createMethod(methodTemplate.getName(), returnType);
        // 添加参数列表
        addParametersToMethod(factory, newMethod, methodTemplate);
        if (isInterface) {
            newMethod = handleInterface(factory, newMethod);
        } else {
            if (StringUtils.isNotEmpty(methodTemplate.getApiName())) {
                addApiAnnotationToMethod(factory, newMethod, methodTemplate.getApiName());
                addApiBodyToMethod(factory, psiClass, newMethod, returnType, methodTemplate);
            } else {
                addOverrideToMethod(factory, newMethod);
                addBodyToMethod(factory, psiClass, newMethod, returnType);
            }
        }
        addCommentToMethod(factory, newMethod, methodTemplate);
        return newMethod;
    }

最后的效果

idea插件,如何通过psi文件追加代码背景 为了提高插件的实用性,我们考虑加入代码的追加的功能,简单来讲,就是通过插件

总结

想要基于idea去追加代码,首先需要知道对应的文件的项目路径,并且获取到对应的VirtualFile文件,通过VirtualFile获取到对应的psi文件,最后在psi文件中追加对应的方法即可。

转载自:https://juejin.cn/post/7411724375848861736
评论
请登录