AS/IntelliJ插件開發實踐

目標

輸入

  1. url地址, 可能包含一級域名和二級域名
  2. get/post參數, 鍵值對形式, 可以動態增減
  3. 接口返回的json結構

輸出

  1. 繼承特定類的請求類的java文件
  2. 根據url實現相應的方法
  3. 根據get/post參數創建內部類, 并且實現toString方法, 并且創建對應的構建函數
  4. 根據json結構創建實體類, 并實現toString方法

實現

涉及的行為

  1. 從界面獲取相關值
  2. 使用列表表示參數, 所以需要動態增加/刪除控件
  3. 獲取目錄路徑, 并創建java文件
  4. 往java文件寫入類定義, 變量定義和方法定義
  5. 解析json

實現界面

一個界面一般包含兩個文件, form fileUI class.

form file

類似Android里面的xml布局文件, 用來描述界面的布局. 使用GUI Designer(類似Android Studio的布局預覽器)通過拖動控件來創建靜態布局.
控件分為componentcontainer,關系和Android中的ViewViewGroup差不多, 其中container會要求指定部分僅對container生效的屬性.

一般container使用默認的GridLayoutManager (IntelliJ)就可以滿足要求了.

大小
  1. Horizontal/Vertical Size Policy: 決定了當該component所屬的container大小發生變化時component的尺寸變化規則. 該屬性只有GridLayoutManager具有, 其中可以賦值下面三個值
    a. canShrink: 實際值可以比指定值(preferred size)小.
    b. canGrow: 實際值可以比指定值大.
    c. wantGrow: 實際值會比指定值大. 優先級高于canGrow, 類似match_parent, 會填充container
  2. Preferred Size: 二維數組指定寬高, 對于GridLayoutManager可以單獨指定寬或者高, -1表示該值由動態計算得出.
位置

不同的LayoutManager有不同的位置屬性.
對于GridLayoutManager來說, 整個布局就是一個網格, 通過網格控制component的位置, 跟Excel有點類似.

對于對齊, 是通過HSpacer/VSpacer來占據空間來對齊的.

使用GUI Designer進行布局的時候, 如果是GridLayoutManager, 插入時會有提示插入的行號和列號, 注意網格的嵌套關系就能輕松把控件放在目標位置了, 另外通過拉伸控件可以合并網格.

UI class

布局實際使用的是Swing, 因此在UI class中涉及控件的操作都可以查閱
Swing的官方教程.

關于動態增刪控件, 在Swing中, 在JLIst中的按鈕是不會響應點擊功能的, 不熟悉Swing浪費了很多時間...

動態增加控件

因此不能用JLIst, JTable過于復雜, 因此直接往JPanel中添加控件然后重繪來實現動態增加控件的效果.

具體的代碼參考官方教程, 只記錄遇到的幾個坑:
注意: 下面的說法沒有深究, 有可能是錯誤的.

布局

使用GridLayoutManager不能動態增加網格, 在這里要實現類似列表的效果, 對吼使用的是BoxLayout.

對齊

使用BoxLayout后, 增加控件會自動居中, 需要通過Box.createVerticalGlue()來創建占位控件來把增加的控件頂至頂部實現頂部對齊的效果.

重繪

增加或者刪除控件之后, 需要調用revalidate()repaint()方法來重繪控件才能正常顯示.

獲取輸入值

通過控件獲取輸入值非常簡單, 類似Android, 控件具有各種getXXXX方法來獲取輸入值.

獲取目錄, 創建文件

PSI

插件開發中, 使用PSI Files來表示具體操作的文件.
PSI(Program Structure Interface) file是一個接口, 使用樹狀結構表示文件中的內容.

對于特定的文件一般有相應的子類, 例如PsiJavaFile表示一個Java文件.

如何獲取PSI
  1. 在Action中通過AnActionEvent#getData(LangDataKeys.PSI_FILE)
  2. 在VirtualFile中通過PsiManager.getInstance(project).findFile()
  3. 在Document中通過PsiDocumentManager.getInstance(project).getPsiFile()
  4. 通過psiElement.getContainingFile()從element實例獲取
  5. 在project中的任意位置通過文件名獲取FilenameIndex.getFilesByName(project, name, scope)

這個插件的入口是Action, 所以可以通過Action就能獲取到當前用戶所在的Java文件的PSI實例.
PSI的操作可以參考PSI Cookbook.

獲取目錄

當已經有PsiFile實例時, 可以通過獲取PsiFile#getParent()獲取到目錄實例PsiDirectory.

創建類文件

對于Java來說, 可以通過JavaDirectoryService#createClass(dir, fileName)來創建類文件, 同時會返回一個PsiClass實例表示該類.

修改類文件

對于Java, 修改類文件首先要獲取想要修改的對象對應的PsiElement子類實例(下面稱PsiElement元素), 例如類定義對應PsiClass實例, 方法定義對應PsiMethod等等.

在Java文件中所有東西都是用元素表示的. 整個Java文件是一棵元素樹, 根節點是一個PsiClass.

通過PsiElement#add()可以給這個元素添加其他元素.
刪除對象包含的元素則需要調用要刪除的元素PsiElement#delete()方法.

大部分PsiElement都可以通過PsiElementFactory中的相關方法獲取.

修改修飾符

只要部分元素有修飾符, 這部分元素都會繼承PsiModifierListOwner.

通過PsiModifierListOwner#getModifierList()可以獲取修飾符列表PsiModifierList實例.
注意修飾符列表本身也是一個元素.
通過PsiElement#add()方法就可以增加修飾符.
通過遍歷PsiModifierList中包含的元素, 然后調用包含的元素的PsiElement#delete()刪除修飾符.

修改繼承關系

只有類元素有繼承關系.

與修飾符類似, 通過PsiClass#getExtendsList()來獲取繼承關系列表, 然后通過add操作來增加繼承關系.
刪除繼承關系需要PsiClass#getExtendsList().getReferenceElements()來獲取元素, 然后刪除這些元素.

寫入變量

變量元素對應的實例為PsiField, 可以通過PsiElementFactory#createField來創建變量, 創建變量時需要通過PsiType指定變量的類型, 同樣可以通過PsiElementFactory#create

寫入方法

方法元素對應的實例為PsiMethod.
構造函數屬于方法元素, 通過PsiElementFactory#createConstructor()來創建.

方法變量

只有方法元素有方法變量.

可以通過PsiMethod#getParameterList()獲取方法變量列表, 然后修改.
方法變量也是一個元素, 實例是PsiParameter, 同樣可以通過工廠方法創建, 創建時需要指定變量類型.

方法體

方法體也是一個元素, 實例是PsiCodeBlock
通過PsiMethod#getBody()來獲取方法體元素, 然后通過增加statement和expression來寫方法體內容.

理所當然, statement和expression也是元素, 可以通過工廠方法創建.

解析json

解析json需要引入json庫, 右鍵項目有Open Module Settings選項, 打開面板有Dependencies面板, 可以添加依賴.

后續就是簡單的創建類和變量了. 不再累述.

總結

  1. 關鍵是取得PsiFile類實例, 一切文件操作都是以此為根據.
  2. 理解PsiElement元素, 整個文件就是一棵元素樹. 類是元素, 方法是元素, 方法體是元素, 語句是元素, 關鍵字也是元素.
  3. PsiElementFactory是個好東西, 能夠很方便地創建元素, 其中的createXXXFromText更是個黑科技.
  4. 對于Java來說, JavaPsiFacade也是個好東西. 能夠通過名稱獲取PsiClass
  5. 讀寫文件需要使用WriteCommandAction.runWriteCommandAction()來啟用工作線程.
  6. 官方文檔很水, 論壇還湊合.
  7. 方法的使用可以看源碼的注釋. 例如PsiElementFactory的源碼.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容