Java 代碼檢查工具之PMD入門使用詳細教程
介紹
PMD是一個靜態源代碼分析器。它發現瞭常見的編程缺陷,如未使用的變量、空捕獲塊、不必要的對象創建等等。
官網:點這裡
官方文檔:點這裡
使用方式
1、使用插件的方式
下載:File -> Settings -> Plugins -> Marketplace 搜索 “PMDPlugin” ,下載插件。
使用方法:在代碼編輯框或Project 窗口的文件夾、包、文件右鍵,選擇“Run PMD”->“Pre Defined”->“All”,對指定的文件夾、包、文件進行分析,分析結果在控制臺輸出。
2、maven項目引入依賴的方式
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.keafmd</groupId> <artifactId>pdm-test01</artifactId> <version>1.0-SNAPSHOT</version> <!--<dependencies> <dependency> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> <version>3.14.0</version> <type>maven-plugin</type> </dependency> </dependencies>--> <!-- 用於生成錯誤到代碼內容的鏈接 --> <reporting> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> <version>3.14.0</version> </plugin> </plugins> </reporting> </project>
mvn 命令執行
在項目目錄打開cmd窗口,輸入以下命令:
mvn pmd:pmd
分析結果為pmd.html
文件,在項目的target下的site目錄下:
分析結果顯示內容:
3、pmd 命令行的方式
pmd -d 源代碼路徑 -f xml(結果輸出格式) -r 結果保存所在目錄及名稱 -R rulesets/java/unusedcode.xml
例子:
結果存放在制定文件目錄下,格式也為命令語句指定的:
檢測結果內容:
4、Java API的方式 *
官方文檔
需要先引入maven依賴
項目結構
測試代碼
Test01:
package com.keafmd.test01; /** * Keafmd * * @ClassName: Test01 * @Description: 測試1 * @author: 牛哄哄的柯南 * @Date: 2021-03-15 15:29 * @Blog: https://keafmd.blog.csdn.net/ */ public class Test01 { public static void main(String[] args) { int a =100; int b=29; String s ="abc"; System.out.println("hello!"); } }
Test02:
package com.keafmd.test02; /** * Keafmd * * @ClassName: Test02 * @Description: * @author: 牛哄哄的柯南 * @Date: 2021-03-15 15:30 * @Blog: https://keafmd.blog.csdn.net/ */ public class Test02 { public static void main(String[] args) { boolean flag=true; while(flag){ flag=false; } System.out.println("123"); int a =100; int b=29; String s ="abc"; System.out.println("hello!"); } }
pmdArgs方式
命令行接口的方式
最簡單的方法是使用與命令行相同的接口調用PMD
Example :
package com.keafmd; import net.sourceforge.pmd.PMD; /** * Keafmd * * @ClassName: Example * @Description: * @author: 牛哄哄的柯南 * @Date: 2021-03-15 15:51 * @Blog: https://keafmd.blog.csdn.net/ */ public class Example { public static void main(String[] args) { String[] pmdArgs = { "-d", "D:/javaworkspace/pdm-test02/src", "-R", "rulesets/java/quickstart.xml", "-f", "xml", "-r", "D:/pmdreport/pmd-report.xml" }; PMD.main(pmdArgs); } }
PMDConfiguration方式
PmdExample:
package com.keafmd; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.PMDConfiguration; /** * Keafmd * * @ClassName: PmdExample * @Description: * @author: 牛哄哄的柯南 * @Date: 2021-03-15 15:57 * @Blog: https://keafmd.blog.csdn.net/ */ public class PmdExample { public static void main(String[] args) { PMDConfiguration configuration = new PMDConfiguration(); configuration.setInputPaths("D:/javaworkspace/pdm-test/src"); configuration.setRuleSets("rulesets/java/quickstart.xml"); configuration.setReportFormat("html"); configuration.setReportFile("D:/pmdreport/pmd-report.html"); PMD.doPMD(configuration); } }
Programmatically(拓展)
這使您能夠更好地控制處理哪些文件,但也會更加復雜。您還可以提供自己的偵聽器和呈現器。
1. 首先,我們創建一個PMDConfiguration
。目前,這是指定規則集的唯一方法:
PMDConfiguration configuration = new PMDConfiguration(); configuration.setMinimumPriority(RulePriority.MEDIUM); configuration.setRuleSets("rulesets/java/quickstart.xml");
2. 為瞭支持類型解析,PMD還需要訪問已編譯的類和依賴項。這被稱為“生長素路徑”,並且在這裡也進行瞭配置。註意:您可以指定由:
關於Unix系統或;
在Windows下。
configuration.prependClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
3. 那我們需要一個規則工廠。這是使用配置創建的,同時考慮到最低優先級:
RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.createFactory(configuration);
4. PMD操作於DataSource
。您可以收集自己的列表FileDataSource
.
List<DataSource> files = Arrays.asList(new FileDataSource(new File("/path/to/src/MyClass.java")));
5. 對於報告,您可以使用內置渲染器。XMLRenderer
。註意,必須通過設置適當的Writer
打電話start()
。在pmd運行之後,您需要調用end()
和flush()
。那麼你的作者應該收到所有的輸出。
StringWriter rendererOutput = new StringWriter(); Renderer xmlRenderer = new XMLRenderer("UTF-8"); xmlRenderer.setWriter(rendererOutput); xmlRenderer.start();
6. 創建一個RuleContext
。這是上下文實例,在規則實現中是可用的。註意:當在多線程模式下運行時(這是默認的),規則上下文實例將被克隆到每個線程。
RuleContext ctx = new RuleContext();
7. 可以選擇註冊報表偵聽器。這樣你就可以對發現的違規行為立即做出反應。您也可以使用這樣的偵聽器來實現您自己的呈現器。偵聽器必須實現接口。ThreadSafeReportListener
並且可以通過ctx.getReport().addListener(...)
.
ctx.getReport().addListener(new ThreadSafeReportListener() { public void ruleViolationAdded(RuleViolation ruleViolation) { } public void metricAdded(Metric metric) { }
8. 現在,所有的準備工作都完成瞭,PMD可以執行瞭。這是通過調用PMD.processFiles(...)
。此方法調用接受配置、規則集工廠、要處理的文件、規則上下文和呈現器列表。如果不想使用任何渲染器,請提供一個空列表。註意:需要顯式關閉輔助路徑。否則,類或JAR文件可能會保持打開狀態,並且文件資源會泄漏。
try { PMD.processFiles(configuration, ruleSetFactory, files, ctx, Collections.singletonList(renderer)); } finally { ClassLoader auxiliaryClassLoader = configuration.getClassLoader(); if (auxiliaryClassLoader instanceof ClasspathClassLoader) { ((ClasspathClassLoader) auxiliaryClassLoader).close(); } }
9. 呼叫後,您需要完成渲染器end()
和flush()
。然後,您可以檢查呈現的輸出。
renderer.end(); renderer.flush(); System.out.println("Rendered Report:"); System.out.println(rendererOutput.toString());
下面是一個完整的例子:
import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.nio.file.FileSystems; import java.nio.file.FileVisitResult; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.PathMatcher; import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.List; import net.sourceforge.pmd.PMD; import net.sourceforge.pmd.PMDConfiguration; import net.sourceforge.pmd.RuleContext; import net.sourceforge.pmd.RulePriority; import net.sourceforge.pmd.RuleSetFactory; import net.sourceforge.pmd.RuleViolation; import net.sourceforge.pmd.RulesetsFactoryUtils; import net.sourceforge.pmd.ThreadSafeReportListener; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.renderers.XMLRenderer; import net.sourceforge.pmd.stat.Metric; import net.sourceforge.pmd.util.ClasspathClassLoader; import net.sourceforge.pmd.util.datasource.DataSource; import net.sourceforge.pmd.util.datasource.FileDataSource; public class PmdExample2 { public static void main(String[] args) throws IOException { PMDConfiguration configuration = new PMDConfiguration(); configuration.setMinimumPriority(RulePriority.MEDIUM); configuration.setRuleSets("rulesets/java/quickstart.xml"); configuration.prependClasspath("/home/workspace/target/classes"); RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.createFactory(configuration); List<DataSource> files = determineFiles("/home/workspace/src/main/java/code"); Writer rendererOutput = new StringWriter(); Renderer renderer = createRenderer(rendererOutput); renderer.start(); RuleContext ctx = new RuleContext(); ctx.getReport().addListener(createReportListener()); // alternative way to collect violations try { PMD.processFiles(configuration, ruleSetFactory, files, ctx, Collections.singletonList(renderer)); } finally { ClassLoader auxiliaryClassLoader = configuration.getClassLoader(); if (auxiliaryClassLoader instanceof ClasspathClassLoader) { ((ClasspathClassLoader) auxiliaryClassLoader).close(); } } renderer.end(); renderer.flush(); System.out.println("Rendered Report:"); System.out.println(rendererOutput.toString()); } private static ThreadSafeReportListener createReportListener() { return new ThreadSafeReportListener() { @Override public void ruleViolationAdded(RuleViolation ruleViolation) { System.out.printf("%-20s:%d %s%n", ruleViolation.getFilename(), ruleViolation.getBeginLine(), ruleViolation.getDescription()); } @Override public void metricAdded(Metric metric) { // ignored } }; } private static Renderer createRenderer(Writer writer) { XMLRenderer xml = new XMLRenderer("UTF-8"); xml.setWriter(writer); return xml; } private static List<DataSource> determineFiles(String basePath) throws IOException { Path dirPath = FileSystems.getDefault().getPath(basePath); PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.java"); List<DataSource> files = new ArrayList<>(); Files.walkFileTree(dirPath, new SimpleFileVisitor<Path>() { @Override public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException { if (matcher.matches(path.getFileName())) { System.out.printf("Using %s%n", path); files.add(new FileDataSource(path.toFile())); } else { System.out.printf("Ignoring %s%n", path); } return super.visitFile(path, attrs); } }); System.out.printf("Analyzing %d files in %s%n", files.size(), basePath); return files; } }
分析結果
分析結果會根據指定格式輸出在指定文件目錄下。
圖形界面
檢測
D:\MyFile\Tool\pmd-bin-6.32.0\bin 目錄下打開cmd窗口輸入:
cpdgui.bat
自定義規則
D:\MyFile\Tool\pmd-bin-6.32.0\bin 目錄下打開cmd窗口輸入:
designer.bat
自定義規則:不能有變量為keafmd的String類型的變量
String keafmd; //這樣就是不合法的。
Source:
public class KeepingItSerious { Delegator keafmd; // FieldDeclaration public void method() { String keafmd; // LocalVariableDeclaration } }
導出的自定義規則:
<rule name="myrule" language="java" message="不能有變量為keafmd的String類型的變量" class="net.sourceforge.pmd.lang.rule.XPathRule"> <description> 自定義規則 </description> <priority>3</priority> <properties> <property name="version" value="2.0"/> <property name="xpath"> <value> <![CDATA[ //VariableDeclaratorId[@Image = "keafmd" and ../../Type[@TypeImage = "String"]] ]]> </value> </property> </properties> </rule>
到此這篇關於Java 代碼檢查工具之PMD入門使用詳細教程的文章就介紹到這瞭,更多相關Java 代碼檢查工具PMD內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Java使用Tess4J實現圖像識別方式
- 深入瞭解Java I/O 之File類
- Java如何通過File類方法刪除指定文件夾中的全部文件
- 一步步帶你入門Java中File類
- java如何讀取某個文件夾中的全部文件(包括子文件夾)