這篇文章將為大家詳細講解有關如何使用p3c實現(xiàn)自定義代碼規(guī)范檢查,文章內(nèi)容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。
為安塞等地區(qū)用戶提供了全套網(wǎng)頁設計制作服務,及安塞網(wǎng)站建設行業(yè)解決方案。主營業(yè)務為成都做網(wǎng)站、成都網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設、安塞網(wǎng)站設計,以傳統(tǒng)方式定制建設網(wǎng)站,并提供域名空間備案等一條龍服務,秉承以專業(yè)、用心的態(tài)度為用戶提供真誠的服務。我們深信只要達到每一位用戶的要求,就會得到認可,從而選擇與我們長期合作。這樣,我們也可以走得更遠!
p3c,一款代碼規(guī)范的檢查工具,有對應的ide插件,能在編碼過程中對設置的規(guī)則進行提示,便打算對它進行拓展,增加對fastjson檢查是否打開setAutoType特性的檢查。
?p3c主要包括3部分:
PMD實現(xiàn)(p3c-pmd):使用PMDhttps://pmd.github.io/來實現(xiàn)代碼規(guī)范檢查
Intellij IDEA插件
Eclipse插件
?p3c使用了PMD。PMD是一款靜態(tài)代碼掃描工具,該工具可以做到檢查Java代碼中是否含有未使用的變量、是否含有空的抓取塊、是否含有不必要的對象等。PMD使用JavaCC生成解析器來解析源代碼并生成AST(抽象語法樹),通過對AST的檢查可以直接從源代碼文本層面來對代碼進行檢查,在PMD內(nèi)部稱為規(guī)則。即是否符合規(guī)則指的是,窮舉源碼各種可能的寫法,然后在AST上檢查是否出現(xiàn)。而規(guī)則的實現(xiàn),重點便在對AST的處理上。
?關于AST的介紹網(wǎng)上有很多,可以直接搜索,這里重要提兩點:
AST是源代碼的抽象語法結構的樹狀表示
抽象語法樹并不依賴于原語言的語法,也就是說同語法分析階段所采用的上下文無關
?PMD使用JavaCC來生成AST。關于JavaCC也可以在網(wǎng)上查看相關資料,這里不多介紹,只要知道JavaCC是一個詞法分析生成器和語法分析生成器便行。
?PMD官方文檔介紹了自定義規(guī)則的實現(xiàn)步驟,過程比較清晰,這里不贅述,只介紹下本文需要設計的步驟。
?PMD的規(guī)則需要配置在XML文件中
新建如下的空文件表示規(guī)則集
<?xml version="1.0"?> <ruleset name="Custom Rules" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd"> <description> My custom rules </description> <!-- Your rules will come here --> </ruleset> ``` * 在上面的``` ruleset ``` 標簽中引用自定義規(guī)則 ``` <rule ref="pathToYourOwnClass" /> ``` * 配置規(guī)則集 ###### 1.2.2. 配置規(guī)則  可以在 ``` rule ``` 標簽中對某一規(guī)則進行配置 * 配置提示消息和告警級別 ``` <rule ref="pathToYourOwnClass" message="message to show" > <priority>5</priority> </rule> ``` 告警優(yōu)先級分為1-5個level,1最高,5最低 * 配置運行參數(shù) 可以通過 ``` properties ``` 和 ``` propertie ```對類屬性賦值 ###### 1.2.3. 編寫規(guī)則  規(guī)則的編寫比較簡單,PMD已經(jīng)給我們做好了配套的開發(fā)框架和工具,只要確定后規(guī)則出現(xiàn)的情況,按照固定的模式去編寫即可。 * 確定實現(xiàn)方式 可以使用純Java方式實現(xiàn),也可以使用XPath方式實現(xiàn)。 對于純Java方式,PMD框架本身實現(xiàn)了對AST數(shù)的遍歷,用戶只要在遍歷各個節(jié)點的時候,對自定義規(guī)則的各種情況進行分析判斷即可,過程類似與DOM文件的SAX解析,以流和事件的方式來解析AST內(nèi)容。 對于XPath方式,則是將AST作為一個XML數(shù),以XPath的方式來遍歷解析內(nèi)容。 * 根據(jù)測試代碼確定可能出現(xiàn)的情況 PMD自帶了一個designer,可以用來生成對應代碼的AST內(nèi)容。對于本文需要達到的效果,涉及到如下代碼: ``` import com.alibaba.fastjson.parser.ParserConfig; public class NegativeExample { public static void main(String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); } } ``` 在designer中可以得到如下的AST內(nèi)容 ![file](https://oscimg.oschina.net/oscnet/491a18dd2086a3919b55fe84e4de1007549.jpg) 具體內(nèi)容這里就不貼出來了,可以下載desigin然后貼上上面的代碼就會有。 對于本文的需求,需要確定在有import ``` ParserConfig ``` 類的時候,調(diào)用了 ``` setAutoTypeSupport ``` 方法且參數(shù)為 ``` true ```。當然這個條件是不夠嚴謹?shù)?,還需要判斷是否調(diào)用了 ``` ParserConfig ```,也要考慮有通過import導入直接寫全限定名的。但考慮到一般的寫法,以及ide的格式化處理,這樣處理已經(jīng)可以滿足大部分場景了。 * 編寫規(guī)則實現(xiàn)類 確定了規(guī)則的判斷條件,就可以著手寫代碼了。 對于Java方式,可以直接繼承 ```net.sourceforge.pmd.lang.java.rule.AbstractJavaRule ``` 類,然后重寫各種節(jié)點的visit方法即可。 例如如下,用于判斷是否有import ``` ParserConfig ``` 類 ``` private final String PARSER_CONFIG_IMPORT_NAME = "com.alibaba.fastjson.parser.ParserConfig"; private boolean hasImport = false; @Override public Object visit(ASTImportDeclaration node, Object data) { if (PARSER_CONFIG_IMPORT_NAME.equals(node.getImportedName())) { hasImport = true; } return super.visit(node, data); } ``` 對于XPath方式,可以通過繼承 ``` net.sourceforge.pmd.lang.rule.XPathRule ``` 類,重寫 ``` setXPath ``` 方法設定對應的XPath即可。上面提到過,可以通過 ``` property ``` 配置對類的屬性進行賦值,因而,對于XPat方式,可以在xml配置中進行如下設置來啟用XPath。 ``` <rule name="My Rule" language="java" message="violation message" class="net.sourceforge.pmd.lang.rule.XPathRule"> <description> Rule Description </description> <priority>3</priority> <properties> <property name="xpath"> <value> <![CDATA[ --- here comes your XPath expression ]]> </value> </property> </properties> ``` ###### 1.2.4. 測試規(guī)則  PMD推薦對于每個規(guī)則,至少要有一個正向和逆向的測試用例,來驗證規(guī)則出現(xiàn)和不出現(xiàn)的情況。對于規(guī)則的測試,PMD也提供了一套框架,只要按照約定好的方式添加xml測試文件即可。  PMD約定了幾個規(guī)則,用來加載測試案例 * 測試類要繼承 ``` net.sourceforge.pmd.testframework.PmdRuleTst ```類,該整合了Junt,可以在里面增加需要的測試方法。 * 對于在 ``` src/test/resource ``` 和測試類對應的路徑下增加一個xml目錄,在增加同第一步同名的xml文件,該文件用于書寫測試集。 例如官網(wǎng)給出的例子 規(guī)則實現(xiàn)類路徑如下: ``` net.sourceforge.pmd.lang.java.rule.bestpractices.AbstractClassWithoutAbstractMethodTest ``` 測試案例集如下: ``` src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AbstractClassWithoutAbstractMethod.xml ``` xml的規(guī)則則可以參考官網(wǎng)介紹,這里不再贅述。 #### 2. p3c-pmd  代碼規(guī)范實現(xiàn)的主要模塊,使用pmd來實現(xiàn)。p3c-pmd模塊在代碼組織上很工整,可以按照相同的模式增加自定義的規(guī)則/規(guī)則集。  對于本文需求,打算在該模塊的基礎上增加一個extend模塊,用于實現(xiàn)自定義規(guī)則集。如下,為對應的源碼路徑好規(guī)則集路徑 ![file](https://oscimg.oschina.net/oscnet/3e3f8a123f38290ab7992a2ac7db6e7d9d0.jpg) ![file](https://oscimg.oschina.net/oscnet/2e451daf3afca20540f4802d6ae072b8c66.jpg)  本文采用純Java方式實現(xiàn)規(guī)則,按照1.2.3.節(jié)的描述,可以得到如下的實現(xiàn)類
public class AvoidFastJsonAutoTypeSupportRule extends AbstractAliRule {
private final String PARSER_CONFIG_IMPORT_NAME = "com.alibaba.fastjson.parser.ParserConfig"; private final String SET_AUTO_TYPE_SUPPORT_NAME = "setAutoTypeSupport"; private boolean hasImport = false; @Override public Object visit(ASTImportDeclaration node, Object data) { if (PARSER_CONFIG_IMPORT_NAME.equals(node.getImportedName())) { hasImport = true; } return super.visit(node, data); } @Override public Object visit(ASTPrimaryExpression node, Object data) { if (hasImport) { int size = node.jjtGetNumChildren(); for (int i = 0; i < size; i++) { Node child = node.jjtGetChild(i); String imageName = null; if (child instanceof ASTPrimaryPrefix) { ASTPrimaryPrefix prefix = (ASTPrimaryPrefix) child; imageName = prefix.jjtGetChild(0).getImage(); }else if (child instanceof ASTPrimarySuffix){ ASTPrimarySuffix suffix = (ASTPrimarySuffix) child; imageName = suffix.getImage(); } if (imageName == null) { continue; }else if (imageName.endsWith(SET_AUTO_TYPE_SUPPORT_NAME)){ ASTPrimarySuffix argumentSuffix = (ASTPrimarySuffix) node.jjtGetChild(i + 1); try { List<Node> booleanArgs = argumentSuffix.findChildNodesWithXPath("//PrimaryPrefix/Literal/BooleanLiteral"); if (booleanArgs.size() == 1) { ASTBooleanLiteral booleanLiteral = (ASTBooleanLiteral) booleanArgs.get(0); if (booleanLiteral.isTrue()) { ViolationUtils.addViolationWithPrecisePosition(this, argumentSuffix, data, I18nResources.getMessage("java.extend.AvoidFastJsonAutoTypeSupportRule.rule.msg" )); } } } catch (JaxenException e) { e.printStackTrace(); } finally { break; } } } } return super.visit(node, data); }
}
 對應規(guī)則集中的配置為
<rule name="AvoidFastJsonAutoTypeSupportRule" language="java" message="java.extend.AvoidFastJsonAutoTypeSupportRule.rule.msg" class="com.alibaba.p3c.pmd.lang.java.rule.extend.AvoidFastJsonAutoTypeSupportRule"> <description>java.extend.AvoidFastJsonAutoTypeSupportRule.rule.desc</description> <priority>1</priority> <example> <![CDATA[ Negative example: import com.alibaba.fastjson.parser.ParserConfig;
public class NegativeExample { public static void main(String[] args) { ParserConfig.getGlobalInstance().setAutoTypeSupport(true); } }
]]> </example> </rule>
 這里有幾點需要注意的,類 ``` AvoidFastJsonAutoTypeSupportRule ``` 繼承自 ``` com.alibaba.p3c.pmd.lang.java.rule.AbstractAliRule ```,AbstractAliRule繼承自AbstractJavaRule,重寫了setDescription,setMessage和addViolationWithMessage等方法,這里提到的3個方法,增加了多語言支持。p3c-pmd使用Resource Bundle來提供多語言支持。每個消息都有一個唯一id來對應,p3c-pmd通過重寫方法,將方法參數(shù)映射為消息的id,以統(tǒng)一消息的配置。如下為本地對應的消息提示內(nèi)容
<!--extend--> <entry key="java.extend.AvoidFastJsonAutoTypeSupportRule.rule.msg"> <![CDATA[不要打開fastjson的setAutoTypeSupport特性]]> </entry> <entry key="java.extend.AvoidFastJsonAutoTypeSupportRule.rule.desc"> <![CDATA[
說明:fastjson的setAutoTypeSupport特性存在安全漏洞 ]]> </entry>
 對于測試,按照1.2.4.的介紹,則有如下的文件路徑 ![file](https://oscimg.oschina.net/oscnet/67322e2edc5dcc7d1e8148149930404a64d.jpg) 文件內(nèi)容比較簡單,這里就不貼出來了。  至此,已經(jīng)完成了自定義規(guī)則的實現(xiàn),現(xiàn)在就是要把該內(nèi)容應用到ide上了。首先,需要將該模塊進行編譯,這里直接保存到本地maven參考,好在本地調(diào)試。  直接將p3c-pmd的版本升級為2.0.1,然后執(zhí)行mvn install,可以在本地倉庫看到對應的版本 ![file](https://oscimg.oschina.net/oscnet/fe9ed36fd7ef30cb794e550782ee4d5d4c3.jpg) 有了該版本,則可以在其他模塊引用該版本進行新功能調(diào)試,下面將以idea-plugin模塊為例。 #### 3. idea-plugin  idea-plugin主要實現(xiàn)了idea的插件,能夠對代碼進行實時檢查。這里涉及到idea自定義插件的開發(fā),這里就不深入了,網(wǎng)上有很多教程。這里只介紹如何將上面自定義的規(guī)則接入該模塊。 1.修改idea-plugin模塊的build.gradle文件,開啟本地倉庫配置,以便從本地直接加載最新的p3c-pmd依賴。
buildscript { repositories { maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } maven { url 'http://dl.bintray.com/jetbrains/intellij-plugin-service' } mavenLocal() mavenCentral()
} dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" }
}
allprojects { group 'com.alibaba.p3c.idea' apply plugin: 'java' apply plugin: 'kotlin' apply plugin: 'maven-publish'
sourceCompatibility = 1.8 compileJava.options.encoding = 'UTF-8' configurations.all { resolutionStrategy.cacheChangingModulesFor 0, 'seconds' } repositories { mavenLocal() jcenter() mavenCentral() } dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" testCompile group: 'junit', name: 'junit', version: '4.11' }
}
如上,增加了```mavenLocal()``` 2.修改p3c-common的build.gradle,更改p3c-pmd的版本為2.0.1 3.修改p3c-common模塊resources/rulesets/java/ali=pmd.xml,增加
<rule ref="rulesets/java/ali-extend.xml"/> ```
以增加自定義規(guī)則檢查。
4.在p3c-common模塊下,執(zhí)行gradle clean buildPlugin
,生成對應的插件。
?本地安裝該插件,可以得到如下效果
這里只驗證效果,沒有真正引入fastjson依賴,也驗證了pmd檢查的是源碼文本。
關于如何使用p3c實現(xiàn)自定義代碼規(guī)范檢查就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。
分享文章:如何使用p3c實現(xiàn)自定義代碼規(guī)范檢查
分享鏈接:http://muchs.cn/article46/pihceg.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供域名注冊、網(wǎng)站改版、網(wǎng)站設計、手機網(wǎng)站建設、響應式網(wǎng)站、做網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)