交流群:462197261站长百科站长论坛热门标签收藏本站北冥有鱼 互联网前沿资源第一站 助力全行业互联网+
点击这里给我发消息
  • 当前位置:
  • 详解基于IDEA2020.1的JAVA代码提示插件开发例子

    之前因为项目组有自己的代码规范,为了约束平时的开发规范,于是基于2019.1.3版本开发了一个代码提示的插件。但是在把IDEA切换到2020.1版本的时候,却发现疯狂报错,但是网上关于IDEA插件开发的相关文章还是不够多,只能自己解决。于是根据官方的SDK文档,使用Gradle重新构建了一下项目,把代码拉了过来。下文会根据2020.1版本简单开发一个代码异常的提示插件,把容易踩坑的地方提示一下。

    1、首先先根据IDEA插件开发官方文档,用Gradle新建一个project

    选中file -> new -> Project...,在弹出的窗口左侧选择Gradle,弹出以下界面:

    默认勾选了Java,需要额外勾选IntelliJ Platform Plugin来表示这是一个IDEA插件项目,还需要勾选Kotlin/JVM这一项,为什么要勾选这一项呢,官网是这么介绍的:

    To include support for the Kotlin language in the plugin, check the Kotlin/JVM box (circled in green below.) This option can be selected with or without the Java language.

    也就是说,如果我们开发的插件需要对JAVA代码做支持的话,是要勾选这一项的。所有如果插件是基于JAVA代码检查的话,需要勾选这一个选项。

    勾选完之后,点击next,之后的信息根据自己实际需要填写即可,然后点击finish,然后默默等待Gradle构建项目,如果可以的话挂个梯子,下载包什么的还是挺慢的。

    构建完后的项目的目录结构以及每一个目录的作用,可以直接去看官方文档,里面有介绍。

    https://www.jetbrains.org/intellij/sdk/docs/tutorials/build_system/prerequisites.html

    2、 构建完项目后,需要修改build.gradle部分配制

    构建完后,默认会打开build.gradle文件,内容如下:

    plugins {
      id 'java'
      id 'org.jetbrains.intellij' version '0.4.19'
      id 'org.jetbrains.kotlin.jvm' version '1.3.71'
    }
    
    group 'org.example'
    version '1.0-SNAPSHOT'
    
    repositories {
      mavenCentral()
    }
    
    dependencies {
      implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
      testCompile group: 'junit', name: 'junit', version: '4.12'
    }
    
    // See https://github.com/JetBrains/gradle-intellij-plugin/
    intellij {
      version '2020.1'
    }
    compileKotlin {
      kotlinOptions.jvmTarget = "1.8"
    }
    compileTestKotlin {
      kotlinOptions.jvmTarget = "1.8"
    }
    patchPluginXml {
      changeNotes """
       Add change notes here.<br>
       <em>most HTML tags may be used</em>"""
    }

    这里有个坑,构建完后,我把以前的代码复制过来,提醒我有部分类没有找到,也就是说没有引入对应的jar包。后来我在官网例子里面发现,它的build.gradle文件,和我的build文件有点不一样,具体不一样的地方如下:

    // See https://github.com/JetBrains/gradle-intellij-plugin/
    intellij {
     version = '2020.1'
     plugins = ['java']
     sameSinceUntilBuild = true
    }

    它在intellij里面,多了一个plugins = ['java']的选项,如果缺少这个选项的话,会缺少java-api.jar等jar等JAVA代码支持的jar包,导致一些类或者方法不可用。所以如果是JAVA代码支持的话,build.gradle文件需要加上plugins = ['java']这一行。

    3、修改plugin.xml文件

    plugin.xml文件是对于本插件的作用的一些描述,以及一些依赖关系配制,构建完后的plugin.xml文件内容如下:

    <idea-plugin>
      <id>org.example.new-plugin-for-java</id>
      <name>Plugin display name here</name>
      <vendor email="support@yourcompany.com" url="http://www.yourcompany.com">YourCompany</vendor>
    
      <description><![CDATA[
      Enter short description for your plugin here.<br>
      <em>most HTML tags may be used</em>
      ]]></description>
    
      <!-- please see https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
         on how to target different products -->
      <depends>com.intellij.java</depends>
    
      <extensions defaultExtensionNs="com.intellij">
        <!-- Add your extensions here -->
        <localInspection
            language="JAVA"
            displayName="test displayer"
            groupPath="Java"
            groupBundle="messages.InspectionsBundle"
            groupKey="group.names.probable.bugs"
            enabledByDefault="true"
            level="ERROR"
            implementationClass="com.nw.TestInsepction"/>
      </extensions>
    
      <actions>
        <!-- Add your actions here -->
      </actions>
    </idea-plugin>

    这里有个坑,如果是IDEA2019.2以前的版本的话,这个文件不用其他东西,直接参考网上的插件开发教程,写好代码,就可以正常运行了。但是如果是IDEA2019.2的版本的话,运行的时候会疯狂报错,一开始不知道为什么,只能又去翻官方的例子,玩大家一起来找不同,结果发现官网的例子,下面的配置信息和默认构建的不一样:

     <!-- Evaluates java PSI -->
     <depends>com.intellij.modules.java</depends>
    

    原来这里的依赖还要改一下,改成上面这样,那为什么要改成这个依赖呢,这个时候,我才发现默认构建的plugin.xml里面,在depends上面有一段注释,大概意思就是,请前往注释里面的网站去找到如何根据产品去选择对应的depends,那就很简单了,直接上网页看,里面很多的介绍,以及各种不同的depends是干嘛的。网页里面有这么一段话:

    (2) The Java language functionality was extracted as a plugin in version 2019.2 of the IntelliJ Platform. This refactoring separated the Java implementation from the other, non-language portions of the platform. Consequently, Java dependencies are expressed differently in plugin.xml depending on the version of the IntelliJ Platform being targeted:

    Syntax required for releases prior to 2019.2, allowable in all releases:

    • plugin.xml include com.intellij.modules.java

    Syntax for 2019.2 and later releases:

    • plugin.xml allowable alternative include com.intellij.java
    • build.gradle required to include intellij.plugins 'java'

    大概意思是,从2019.2版本开始后,java代码相关的支持抽成了一个插件,不包含在默认构建的包里面了,所以从2019.2版本开始后,plugin.xmlbuild.gradle需要修改成相关的配置。这也是为什么我们第二步要改build.gradle的原因。

    4、参考网上的例子,编写第一个代码提示插件

    新建一个java类,内容如下,这是一个测试用的提示插件,在所有变量上面提示"this is error"

    package com;
    
    import com.intellij.codeInspection.AbstractBaseJavaLocalInspectionTool;
    import com.intellij.codeInspection.ProblemsHolder;
    import com.intellij.psi.JavaElementVisitor;
    import com.intellij.psi.PsiElementVisitor;
    import com.intellij.psi.PsiField;
    import org.jetbrains.annotations.NotNull;
    
    /**
     * 这是一个测试用的提示插件,在所有变量上面提示"this is an error"
     * @author LiuYeFeng
     * @date 2020/5/5
     * @e-mail nightwind666@163.com
     */
    public class TestInspectionTool extends AbstractBaseJavaLocalInspectionTool {
    
      @NotNull
      @Override
      public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly) {
        // 返回一个java元素的访问器,重写当访问变量的时候,需要做的操作
        return new JavaElementVisitor() {
          @Override
          public void visitField(PsiField field) {
            super.visitField(field);
            // 注册问题,也就是在变量上面显示异常红色下划线,并提示"this is an error"
         		// 如果可以的话,这里也可以附带上快速修复问题的方法
            holder.registerProblem(field, "this is an error");
          }
        };
      }
    }

    然后在plugin.xml里面的extensions添加上面编写的插件,如下;

     <extensions defaultExtensionNs="com.intellij">
        <!-- Add your extensions here -->
        <localInspection
            language="JAVA"
            displayName="Test field error"
            groupPath="Java"
            groupBundle="messages.InspectionsBundle"
            groupKey="group.names.probable.bugs"
            enabledByDefault="true"
            level="ERROR"
            implementationClass="com.TestInspectionTool"/>
      </extensions>

    以上配置大致是注册一个代码提示组件,里面的参数会决定你的提示配置在IDEA的哪个分类里面,以及提示的等级,例子里面用ERROR级别,可以查看的简单一点。

    5、开始看代码提示插件的效果

    点击右上角的debug,等待编译运行。运行后会弹出一个新的IDEA,这个IDEA会加载了我们编写的插件,同时在我们原来编写插件的IDEA可以看到日志输出等东西,也可以断点。可以简单理解为新的IDEA是一个浏览器,我们在用网页调试后端接口。

    因为我们编写的插件是新写一个变量,不管三七二十一就会报错,提示this is an error,效果如下;

    到此,一个完成的代码异常提示插件,就简单完成了。

    6、代码提示插件还可以做到的

    我们编写的这个插件,其实是比较简单的,并没有做逻辑分析。我们是可以根据实际需要,去编写一些项目组本身特有的功能的,例如某些继承自特殊类的所有字段,必须要有注释。在Service里面的方法,异常返回之前必须要记录日志或者一些其他操作等,都是可以做到的,还可以做一些快速修复(quick fix),例如字段没有注释可以快速生成注释。

    这就需要对IDEA语法树相关有了解,IDEA把代码抽象成了Psi语法树,根据不同的代码功能划分为不同的PsiElement,例如注释是PsiComment,字段是PsiField,方法是PsiMethod,类是PsiClass。IDEA本身也提供了相当多的工具类,例如ReferencesSearch可以寻找类或者方法的引用点,PsiTreeUtil可以处理代码语法树上面的一些操作,例如获取变量所在的方法,ControlFlowUtil可以对代码进行解析等,还有PsiClassUtilPsiFieldUtil等各种相关性的工具类可以提供各种便捷的操作,这就需要插件开发者自己去摸索。遇到问题可以去IDEA官方问答论坛去找一下,说不定别人已经帮你解决了这个问题了。

    附加:

    IntelliJ Platform SDK官网

    https://www.jetbrains.org/intellij/sdk/docs/intro/welcome.html

    IntelliJ 插件开发交流社区

    https://intellij-support.jetbrains.com/hc/en-us/community/topics/200366979-IntelliJ-IDEA-Open-API-and-Plugin-Development

    到此这篇关于详解基于IDEA2020.1的JAVA代码提示插件开发例子的文章就介绍到这了,更多相关IDEA2020.1 JAVA代码提示插件内容请搜索北冥有鱼以前的文章或继续浏览下面的相关文章希望大家以后多多支持北冥有鱼!


    广而告之:
    热门推荐:
    js模态对话框使用方法详解

    模态框(Modal  Dialogue Box)也可叫做模态对话框,或者对话框,当一个模态框被打开时,用户可以与该对话框进行交互,点击关闭按钮可关闭该模态框! 功能实现: 1. 页面上有一个按钮,用于打开模态框,模态框默认隐藏; 2. 用户点击按钮,可打开模态框;用户点击模态框···

    网页设计师是一个符合型人才

    世间本没有路。走的人多了就成了路,网页设计一开始没有人把它当作一种谋生的手段,其本上全是个人兴趣,业余爱好,可爱好却爱出了一个职业,后来还美其名曰:网页设计师。 什么是网页设计师? 在我的个人观念里,网页设计师不同于美工。网页设计师是在美工和后台程序员之间的···

    深入理解Angular2 模板语法

    1. 说明 Angular2的模板用来显示组件外观,作为视图所用,用法和html语法基本一致,最简单的Angular2的模板就是一段html代码。Angular模板语法主要包括以下几个部分: l 直接绑定 l 插值表达 l 属性绑定 l 事件绑定 l 双向绑定 l 样式绑定 l 模板和 * l 局部变量 首先来看一个···

    linux服务器清空MySQL的history历史记录 删除mysql操作记录

    1. 不再保存历史记录或者减少历史记录保存数量 修改/etc/profile将HISTSIZE=1000 改成 0 或 要保留的数量清除用户home路径下的 .bash_history 复制代码 代码如下:echo '' > /home/user/.bash_history 2. 立即清空里的history当前历史命令的记录 复制代码 代码如下:his···

    JS 正则表达式验证密码、邮箱格式的实例代码

    遗憾的是博客内容不允许包含js代码,不能在线测试,就只上代码了 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Regular Expression test</title> </head> <body> 用户名:(4-16位,字母、下划线、数···

    ES6数组的扩展详解

    本文实例讲述了ES6数组的扩展。分享给大家供大家参考,具体如下: 1. Array.from() Array.from()将类数组(array-like)对象与可遍历的对象转化为数组并返回。 下面是一个类数组 let arr = { '0':'a', '1':'b', '2':'c', length:3 }; ES5我们可能都会这样写: var ar···

    JS访问SWF的函数用法实例

    本文实例讲述了JS访问SWF的函数用法。分享给大家供大家参考。具体分析如下: 关于Flash和JS相互调用的例子已经说很多了,这不是难题,当然,调用错误这也不是Flash和JS的错误,我们今天就来彻底解决IE,FF和Chrome之间的不兼容问题! 我们知道,Flash中,如果访问外部JS函数,···

    网站质量从哪几方面优化?保持网站优化的重要细节有哪些?

    我们做SEO都知道,在网站优化的过程中,网站细节的优化是非常重要的。目前,搜索引擎对网站质量的要求越来越高。那么,作为网站管理员,我们应该如何不断地对网站的质量进行优化呢?织梦58SEO小编认为很长一段时间内保持良好的网站优化是非常重要的。 那么,作为一个网站管···

    php 使用file

    当我们遇到文本文件体积很大时,比如超过几十M甚至几百M几G的大文件,用记事本或者其它编辑器打开往往不能成功,因为他们都需要把文件内容全部放到内存里面,这时就会发生内存溢出而打开错误,遇到这种情况我们可以使用PHP的文件读取函数file_get_contents()进行分段读取。 函···

    完美解决IE不支持Data.parse()的问题

    IE不能识别JS函数Date.parse的解决方法  ,当我们用JS计算两个时间的间隔时,我们会用到Date.parse 这个JS函数。 如: var begintime = "2012-12-22"; //开始时间 var endtime = "2012-12-25"; //结束时间 var begindate=new Date(begintime); var enddate=new Da···