IDEA是一个非常强大的工具,对于提高编程效率有非常大的帮助。当然他也不是全能的,有时候的一些需求他可能并没有办法直接满足,这个时候一般就需要通过他的插件来完成了。
目前Idea已经有了非常多的插件可以使用,但有时候可能现有插件并不能满足自己的需求,我就遇到了两个,如生成Bean的Setter方法时,想要同时生成void类型的Setter以及返回Bean类型的Setter方法,并未找到好的插件来使用。于是只好自己研究来写一个。但在写的过程中实在感觉非常的痛苦,它的Api使用起来非常麻烦,在刚开始时简直就没法忍受下去。实际上写完一两个插件后,也会基本也熟悉了他这一套的用法,但实际上还是会忍不住想要吐槽下。写完两个插件后就想着将这些觉用法总结下,以便即使时间长了也有个地方可以翻阅下,不至于后面再要想写的时候又要痛苦一番。
IDEA的插件开发最好是通过IDEA开发工具来进行。
首先创建工程,选择Intellij Platform Plugin类型,其它默认。
创建完成后会发现有一个resources的目录和一个src的目录,在resources/META-INF中有一个plugin.xml的文件,这个文件就是对插件的一些描述及配置,如我们可以指定插件安装后新增的菜单项路径及名称、指定菜单项点击后将会触发的事件等。下面是一个典型的配置:
<idea-plugin>
<id>cn.liumoran.toolsid>
<name>GetterSetterGeneratorname>
<version>1.0version>
<vendor email="[email protected]" url="http://liumoran.cn">刘奇vendor>
<description>Idea的Setter与Getter方法生成器。默认的生成器只能生成常规的Getter与Setter方法,或者Builder模式的Setter与Getter方法,而不能两者共存。使用本插件,
针对一个属性可以生成三个方法,其中一个Getter方法,一个void的Setter方法及一个Builder模式的Setter方法description>
<idea-version since-build="173.0"/>
<extensions defaultExtensionNs="com.intellij">
extensions>
<actions>
<action class="GetterSetterGenerateAction" id="setterGenerator" text="generate setters/getters" keymap="">
<add-to-group group-id="WindowMenu" anchor="first"/>
action>
actions>
idea-plugin>
其中action中的内容最为关键,它指定了菜单项的位置以及点击菜单项后将要执行的Action的哪个。
指定的Action就对应于项目中定义的一个AnAction对象,所有的逻辑处理就都在这个Action中进行,其中最为关键的就是actionPerformed方法。它的定义如下:
public void actionPerformed(@NotNull AnActionEvent anActionEvent) {}
可以看到它接收的是一个AnActionEvent的对象,通过这个事件对象,我们可以获取到当前所在的项目、当前编辑的文件等。
插件开发完成后,我们可以点击Builder->Prepare Plugin module…这个菜单来生成JAR包,生成后即可通过Idea的插件安装工具通过安装本地文件的方式来进行插件的安装。
插件开发的主要流程就是这样,接下来主要说明在插件开发过程中可能会使用到的各种应用场景如何去实现。
先介绍下几个常用的对象(JAVA相关应用里面):
插件开发中一般都是对这些对象进行操作。下面来看常用的一些操作:
获取当前项目:
Project project = anActionEvent.getProject();
获取当前的编辑器对象:
Editor editor = anActionEvent.getData(CommonDataKeys.EDITOR);
获取当前编辑的文件:
PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
// 如果是Java文件,可以转换成PsiJavaFile
PsiJavaFile javaFile = (PsiJavaFile)psiFile;
获取JavaFile中的Class:
// 一个文件中可能会定义有多个Class,因此返回的是一个数组
PsiClass[] classes = javaFile.getClasses();
PsiClass的常用方法:
在Class中创建Field:
PsiElementFactory elementFactory = PsiElementFactory.SERVICE.getInstance(project);
PsiField cField = elementFactory.createFieldFromText(annotationStringBuilder.toString() + "private String test;", null);
aClass.add(cField);
在Class中创建Method:
PsiMethod method = elementFactory.createMethodFromText("public void test(){}", null);
aClass.add(method);
判断Class或者Field是否包含有某个注解及获取注解属性值:
PsiAnnotation psiAnnotation = field.getAnnotation("javax.persistence.Column");
PsiAnnotationMemberValue memberValue = psiAnnotation.findAttributeValue("columnDefinition");
if (null != memberValue) {
String str = memberValue.getText();
}
Import某个类:由于引入类操作是在File中进行的,因此在Class类上是没有办法导入的,如果已经获取到了javaFile对象,那么可以这样导入,否则需要先获取到Class所在的File后再进行导入:
javaFile.importClass(aClass);
根据class获取所在文件:
(PsiJavaFile) aClass.getContainingFile()
获取类所在包:
// 先获取到文件后再获取文件所在包
String daoPackage = ((PsiJavaFile) aClass.getContainingFile()).getPackageName();
创建文件(包含文件中的类):
javaFile = (PsiJavaFile) PsiFileFactory.getInstance(project).createFileFromText("Test.java", JavaFileType.INSTANCE, "public class Test {}");
获取当前文件所在包:
PsiDirectory containerDirectory = javaFile.getContainingDirectory();
创建子包(子目录):
parentDirectory.createSubdirectory("test");
将文件添加到包中去
psiDirectory.add(javaFile);
查找类:
PsiShortNamesCache shortNamesCache = PsiShortNamesCache.getInstance(project);
PsiClass[] classes = shortNamesCache.getClassesByName("Test", GlobalSearchScope.allScope(project));
获取Resource目录:
ModuleRootManager rootManager = ModuleRootManager.getInstance(module);
List<VirtualFile> sourceRoots = rootManager.getSourceRoots(JavaModuleSourceRootTypes.RESOURCES);
VirtualFile resourceDirectory = sourceRoots.get(0);
创建xml文件并加入到某个目录:
// content对应于XML文件内容
psiFile = PsiFileFactory.getInstance(project).createFileFromText(fileName, XMLLanguage.INSTANCE,content);
psiDirectory.add(psiFile);
最后本人写了两个插件,一个是Bean的Setter与Getter生成插件,地址:http://liumoran.cn/articleDetail/199; 一个是根据Entity对象生成DTO、Service、Controller等相关对象,地址:http://liumoran.cn/articleDetail/200,有兴趣的可以关注下。