詳解基于IDEA2020.1的JAVA代碼提示插件開(kāi)發(fā)例子
之前因?yàn)轫?xiàng)目組有自己的代碼規(guī)范,為了約束平時(shí)的開(kāi)發(fā)規(guī)范,于是基于2019.1.3版本開(kāi)發(fā)了一個(gè)代碼提示的插件。但是在把IDEA切換到2020.1版本的時(shí)候,卻發(fā)現(xiàn)瘋狂報(bào)錯(cuò),但是網(wǎng)上關(guān)于IDEA插件開(kāi)發(fā)的相關(guān)文章還是不夠多,只能自己解決。于是根據(jù)官方的SDK文檔,使用Gradle重新構(gòu)建了一下項(xiàng)目,把代碼拉了過(guò)來(lái)。下文會(huì)根據(jù)2020.1版本簡(jiǎn)單開(kāi)發(fā)一個(gè)代碼異常的提示插件,把容易踩坑的地方提示一下。
1、首先先根據(jù)IDEA插件開(kāi)發(fā)官方文檔,用Gradle新建一個(gè)project
選中file -> new -> Project...
,在彈出的窗口左側(cè)選擇Gradle
,彈出以下界面:
默認(rèn)勾選了Java,需要額外勾選IntelliJ Platform Plugin
來(lái)表示這是一個(gè)IDEA插件項(xiàng)目,還需要勾選Kotlin/JVM
這一項(xiàng),為什么要勾選這一項(xiàng)呢,官網(wǎng)是這么介紹的:
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.
也就是說(shuō),如果我們開(kāi)發(fā)的插件需要對(duì)JAVA代碼做支持的話(huà),是要勾選這一項(xiàng)的。所有如果插件是基于JAVA代碼檢查的話(huà),需要勾選這一個(gè)選項(xiàng)。
勾選完之后,點(diǎn)擊next,之后的信息根據(jù)自己實(shí)際需要填寫(xiě)即可,然后點(diǎn)擊finish,然后默默等待Gradle構(gòu)建項(xiàng)目,如果可以的話(huà)掛個(gè)梯子,下載包什么的還是挺慢的。
構(gòu)建完后的項(xiàng)目的目錄結(jié)構(gòu)以及每一個(gè)目錄的作用,可以直接去看官方文檔,里面有介紹。
https://www.jetbrains.org/intellij/sdk/docs/tutorials/build_system/prerequisites.html
2、 構(gòu)建完項(xiàng)目后,需要修改build.gradle部分配制
構(gòu)建完后,默認(rèn)會(huì)打開(kāi)build.gradle
文件,內(nèi)容如下:
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>""" }
這里有個(gè)坑,構(gòu)建完后,我把以前的代碼復(fù)制過(guò)來(lái),提醒我有部分類(lèi)沒(méi)有找到,也就是說(shuō)沒(méi)有引入對(duì)應(yīng)的jar包。后來(lái)我在官網(wǎng)例子里面發(fā)現(xiàn),它的build.gradle
文件,和我的build文件有點(diǎn)不一樣,具體不一樣的地方如下:
// See https://github.com/JetBrains/gradle-intellij-plugin/ intellij { version = '2020.1' plugins = ['java'] sameSinceUntilBuild = true }
它在intellij里面,多了一個(gè)plugins = ['java']
的選項(xiàng),如果缺少這個(gè)選項(xiàng)的話(huà),會(huì)缺少java-api.jar
等jar等JAVA代碼支持的jar包,導(dǎo)致一些類(lèi)或者方法不可用。所以如果是JAVA代碼支持的話(huà),build.gradle
文件需要加上plugins = ['java']
這一行。
3、修改plugin.xml文件
plugin.xml
文件是對(duì)于本插件的作用的一些描述,以及一些依賴(lài)關(guān)系配制,構(gòu)建完后的plugin.xml
文件內(nèi)容如下:
<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>
這里有個(gè)坑,如果是IDEA2019.2以前的版本的話(huà),這個(gè)文件不用其他東西,直接參考網(wǎng)上的插件開(kāi)發(fā)教程,寫(xiě)好代碼,就可以正常運(yùn)行了。但是如果是IDEA2019.2的版本的話(huà),運(yùn)行的時(shí)候會(huì)瘋狂報(bào)錯(cuò),一開(kāi)始不知道為什么,只能又去翻官方的例子,玩大家一起來(lái)找不同,結(jié)果發(fā)現(xiàn)官網(wǎng)的例子,下面的配置信息和默認(rèn)構(gòu)建的不一樣:
<!-- Evaluates java PSI --> <depends>com.intellij.modules.java</depends>
原來(lái)這里的依賴(lài)還要改一下,改成上面這樣,那為什么要改成這個(gè)依賴(lài)呢,這個(gè)時(shí)候,我才發(fā)現(xiàn)默認(rèn)構(gòu)建的plugin.xml
里面,在depends上面有一段注釋?zhuān)蟾乓馑季褪牵?qǐng)前往注釋里面的網(wǎng)站去找到如何根據(jù)產(chǎn)品去選擇對(duì)應(yīng)的depends,那就很簡(jiǎn)單了,直接上網(wǎng)頁(yè)看,里面很多的介紹,以及各種不同的depends是干嘛的。網(wǎng)頁(yè)里面有這么一段話(huà):
(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
includecom.intellij.modules.java
Syntax for 2019.2 and later releases:
plugin.xml
allowable alternative includecom.intellij.java
build.gradle
required to includeintellij.plugins 'java'
大概意思是,從2019.2版本開(kāi)始后,java代碼相關(guān)的支持抽成了一個(gè)插件,不包含在默認(rèn)構(gòu)建的包里面了,所以從2019.2版本開(kāi)始后,plugin.xml
和build.gradle
需要修改成相關(guān)的配置。這也是為什么我們第二步要改build.gradle
的原因。
4、參考網(wǎng)上的例子,編寫(xiě)第一個(gè)代碼提示插件
新建一個(gè)java類(lèi),內(nèi)容如下,這是一個(gè)測(cè)試用的提示插件,在所有變量上面提示"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; /** * 這是一個(gè)測(cè)試用的提示插件,在所有變量上面提示"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) { // 返回一個(gè)java元素的訪(fǎng)問(wèn)器,重寫(xiě)當(dāng)訪(fǎng)問(wèn)變量的時(shí)候,需要做的操作 return new JavaElementVisitor() { @Override public void visitField(PsiField field) { super.visitField(field); // 注冊(cè)問(wèn)題,也就是在變量上面顯示異常紅色下劃線(xiàn),并提示"this is an error" // 如果可以的話(huà),這里也可以附帶上快速修復(fù)問(wèn)題的方法 holder.registerProblem(field, "this is an error"); } }; } }
然后在plugin.xml
里面的extensions
添加上面編寫(xiě)的插件,如下;
<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>
以上配置大致是注冊(cè)一個(gè)代碼提示組件,里面的參數(shù)會(huì)決定你的提示配置在IDEA的哪個(gè)分類(lèi)里面,以及提示的等級(jí),例子里面用ERROR級(jí)別,可以查看的簡(jiǎn)單一點(diǎn)。
5、開(kāi)始看代碼提示插件的效果
點(diǎn)擊右上角的debug,等待編譯運(yùn)行。運(yùn)行后會(huì)彈出一個(gè)新的IDEA,這個(gè)IDEA會(huì)加載了我們編寫(xiě)的插件,同時(shí)在我們?cè)瓉?lái)編寫(xiě)插件的IDEA可以看到日志輸出等東西,也可以斷點(diǎn)??梢院?jiǎn)單理解為新的IDEA是一個(gè)瀏覽器,我們?cè)谟镁W(wǎng)頁(yè)調(diào)試后端接口。
因?yàn)槲覀兙帉?xiě)的插件是新寫(xiě)一個(gè)變量,不管三七二十一就會(huì)報(bào)錯(cuò),提示this is an error
,效果如下;
到此,一個(gè)完成的代碼異常提示插件,就簡(jiǎn)單完成了。
6、代碼提示插件還可以做到的
我們編寫(xiě)的這個(gè)插件,其實(shí)是比較簡(jiǎn)單的,并沒(méi)有做邏輯分析。我們是可以根據(jù)實(shí)際需要,去編寫(xiě)一些項(xiàng)目組本身特有的功能的,例如某些繼承自特殊類(lèi)的所有字段,必須要有注釋。在Service里面的方法,異常返回之前必須要記錄日志或者一些其他操作等,都是可以做到的,還可以做一些快速修復(fù)(quick fix),例如字段沒(méi)有注釋可以快速生成注釋。
這就需要對(duì)IDEA語(yǔ)法樹(shù)相關(guān)有了解,IDEA把代碼抽象成了Psi語(yǔ)法樹(shù),根據(jù)不同的代碼功能劃分為不同的PsiElement
,例如注釋是PsiComment
,字段是PsiField
,方法是PsiMethod
,類(lèi)是PsiClass
。IDEA本身也提供了相當(dāng)多的工具類(lèi),例如ReferencesSearch
可以尋找類(lèi)或者方法的引用點(diǎn),PsiTreeUtil
可以處理代碼語(yǔ)法樹(shù)上面的一些操作,例如獲取變量所在的方法,ControlFlowUtil
可以對(duì)代碼進(jìn)行解析等,還有PsiClassUtil
和PsiFieldUtil
等各種相關(guān)性的工具類(lèi)可以提供各種便捷的操作,這就需要插件開(kāi)發(fā)者自己去摸索。遇到問(wèn)題可以去IDEA官方問(wèn)答論壇去找一下,說(shuō)不定別人已經(jīng)幫你解決了這個(gè)問(wèn)題了。
附加:
https://www.jetbrains.org/intellij/sdk/docs/intro/welcome.html
IntelliJ 插件開(kāi)發(fā)交流社區(qū)
https://intellij-support.jetbrains.com/hc/en-us/community/topics/200366979-IntelliJ-IDEA-Open-API-and-Plugin-Development
到此這篇關(guān)于詳解基于IDEA2020.1的JAVA代碼提示插件開(kāi)發(fā)例子的文章就介紹到這了,更多相關(guān)IDEA2020.1 JAVA代碼提示插件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java?Float?保留小數(shù)位精度的實(shí)現(xiàn)
這篇文章主要介紹了Java?Float?保留小數(shù)位精度的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Spring?Security實(shí)現(xiàn)接口放通的方法詳解
在用Spring?Security項(xiàng)目開(kāi)發(fā)中,有時(shí)候需要放通某一個(gè)接口時(shí),我們需要在配置中把接口地址配置上,這樣做有時(shí)候顯得麻煩。本文將通過(guò)一個(gè)注解的方式快速實(shí)現(xiàn)接口放通,感興趣的可以了解一下2022-05-05詳解高性能緩存Caffeine原理及實(shí)戰(zhàn)
Caffeine是基于Java 8開(kāi)發(fā)的,提供了近乎最佳命中率的高性能本地緩存組件,Spring5開(kāi)始不再支持Guava Cache,改為使用Caffeine。Caffeine提供的內(nèi)存緩存使用參考Google guava的API2021-06-06Springboot 全局時(shí)間格式化三種方式示例詳解
時(shí)間格式化在項(xiàng)目中使用頻率是非常高的,當(dāng)我們的 API? 接口返回結(jié)果,需要對(duì)其中某一個(gè) date? 字段屬性進(jìn)行特殊的格式化處理,通常會(huì)用到 SimpleDateFormat? 工具處理,這篇文章主要介紹了3 種 Springboot 全局時(shí)間格式化方式,需要的朋友可以參考下2024-01-01mybatis新手快速入門(mén)以及一些錯(cuò)誤匯總
這篇文章主要給大家介紹了關(guān)于mybatis新手快速入門(mén)以及一些錯(cuò)誤的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Java 覆蓋equals時(shí)總要覆蓋hashcode
這篇文章主要介紹了Java 覆蓋equals時(shí)總要覆蓋hashcode的相關(guān)資料,這里附有實(shí)例代碼,具有參考價(jià)值,需要的朋友可以參考下2016-12-12詳解Java中布隆過(guò)濾器(Bloom Filter)原理及其使用場(chǎng)景
布隆過(guò)濾器是1970年由布隆提出的,它實(shí)際上是一個(gè)很長(zhǎng)的二進(jìn)制向量和一系列隨機(jī)映射函數(shù),它的作用是檢索一個(gè)元素是否存在我們的集合之中,本文給大家詳細(xì)的講解一下布隆過(guò)濾器,感興趣的同學(xué)可以參考閱讀2023-05-05RabbitMQ消息隊(duì)列中多路復(fù)用Channel信道詳解
這篇文章主要介紹了RabbitMQ消息隊(duì)列中多路復(fù)用Channel信道詳解,消息Message是指在應(yīng)用間傳送的數(shù)據(jù),消息可以非常簡(jiǎn)單,比如只包含文本字符串,也可以更復(fù)雜,可能包含嵌入對(duì)象,需要的朋友可以參考下2023-08-08Dubbo Service Mesh基礎(chǔ)架構(gòu)組件改造
Service Mesh這個(gè)“熱”詞是2016年9月被“造”出來(lái),而今年2018年更是被稱(chēng)為service Mesh的關(guān)鍵之年,各家大公司都希望能在這個(gè)思潮下領(lǐng)先一步2023-03-03