Java 代碼檢查工具之PMD入門使用詳細(xì)教程
介紹
PMD是一個(gè)靜態(tài)源代碼分析器。它發(fā)現(xiàn)了常見(jiàn)的編程缺陷,如未使用的變量、空捕獲塊、不必要的對(duì)象創(chuàng)建等等。
官網(wǎng):點(diǎn)這里
官方文檔:點(diǎn)這里
使用方式
1、使用插件的方式
下載:File -> Settings -> Plugins -> Marketplace 搜索 “PMDPlugin” ,下載插件。
使用方法:在代碼編輯框或Project 窗口的文件夾、包、文件右鍵,選擇“Run PMD”->“Pre Defined”->“All”,對(duì)指定的文件夾、包、文件進(jìn)行分析,分析結(jié)果在控制臺(tái)輸出。
2、maven項(xiàng)目引入依賴的方式
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>--> <!-- 用于生成錯(cuò)誤到代碼內(nèi)容的鏈接 --> <reporting> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-pmd-plugin</artifactId> <version>3.14.0</version> </plugin> </plugins> </reporting> </project>
mvn 命令執(zhí)行
在項(xiàng)目目錄打開(kāi)cmd窗口,輸入以下命令:
mvn pmd:pmd

分析結(jié)果為pmd.html文件,在項(xiàng)目的target下的site目錄下:


分析結(jié)果顯示內(nèi)容:

3、pmd 命令行的方式
pmd -d 源代碼路徑 -f xml(結(jié)果輸出格式) -r 結(jié)果保存所在目錄及名稱 -R rulesets/java/unusedcode.xml
例子:

結(jié)果存放在制定文件目錄下,格式也為命令語(yǔ)句指定的:

檢測(cè)結(jié)果內(nèi)容:

4、Java API的方式 *
需要先引入maven依賴
項(xiàng)目結(jié)構(gòu)

測(cè)試代碼
Test01:
package com.keafmd.test01;
/**
* Keafmd
*
* @ClassName: Test01
* @Description: 測(cè)試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方式
命令行接口的方式
最簡(jiǎn)單的方法是使用與命令行相同的接口調(diào)用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(拓展)
這使您能夠更好地控制處理哪些文件,但也會(huì)更加復(fù)雜。您還可以提供自己的偵聽(tīng)器和呈現(xiàn)器。
1. 首先,我們創(chuàng)建一個(gè)PMDConfiguration。目前,這是指定規(guī)則集的唯一方法:
PMDConfiguration configuration = new PMDConfiguration();
configuration.setMinimumPriority(RulePriority.MEDIUM);
configuration.setRuleSets("rulesets/java/quickstart.xml");
2. 為了支持類型解析,PMD還需要訪問(wèn)已編譯的類和依賴項(xiàng)。這被稱為“生長(zhǎng)素路徑”,并且在這里也進(jìn)行了配置。注意:您可以指定由:關(guān)于Unix系統(tǒng)或;在Windows下。
configuration.prependClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
3. 那我們需要一個(gè)規(guī)則工廠。這是使用配置創(chuàng)建的,同時(shí)考慮到最低優(yōu)先級(jí):
RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.createFactory(configuration);
4. PMD操作于DataSource。您可以收集自己的列表FileDataSource.
List<DataSource> files = Arrays.asList(new FileDataSource(new File("/path/to/src/MyClass.java")));
5. 對(duì)于報(bào)告,您可以使用內(nèi)置渲染器。XMLRenderer。注意,必須通過(guò)設(shè)置適當(dāng)?shù)?code>Writer打電話start()。在pmd運(yùn)行之后,您需要調(diào)用end()和flush()。那么你的作者應(yīng)該收到所有的輸出。
StringWriter rendererOutput = new StringWriter();
Renderer xmlRenderer = new XMLRenderer("UTF-8");
xmlRenderer.setWriter(rendererOutput);
xmlRenderer.start();
6. 創(chuàng)建一個(gè)RuleContext。這是上下文實(shí)例,在規(guī)則實(shí)現(xiàn)中是可用的。注意:當(dāng)在多線程模式下運(yùn)行時(shí)(這是默認(rèn)的),規(guī)則上下文實(shí)例將被克隆到每個(gè)線程。
RuleContext ctx = new RuleContext();
7. 可以選擇注冊(cè)報(bào)表偵聽(tīng)器。這樣你就可以對(duì)發(fā)現(xiàn)的違規(guī)行為立即做出反應(yīng)。您也可以使用這樣的偵聽(tīng)器來(lái)實(shí)現(xiàn)您自己的呈現(xiàn)器。偵聽(tīng)器必須實(shí)現(xiàn)接口。ThreadSafeReportListener并且可以通過(guò)ctx.getReport().addListener(...).
ctx.getReport().addListener(new ThreadSafeReportListener() {
public void ruleViolationAdded(RuleViolation ruleViolation) {
}
public void metricAdded(Metric metric) {
}
8. 現(xiàn)在,所有的準(zhǔn)備工作都完成了,PMD可以執(zhí)行了。這是通過(guò)調(diào)用PMD.processFiles(...)。此方法調(diào)用接受配置、規(guī)則集工廠、要處理的文件、規(guī)則上下文和呈現(xiàn)器列表。如果不想使用任何渲染器,請(qǐng)?zhí)峁┮粋€(gè)空列表。注意:需要顯式關(guān)閉輔助路徑。否則,類或JAR文件可能會(huì)保持打開(kāi)狀態(tài),并且文件資源會(huì)泄漏。
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()。然后,您可以檢查呈現(xiàn)的輸出。
renderer.end();
renderer.flush();
System.out.println("Rendered Report:");
System.out.println(rendererOutput.toString());
下面是一個(gè)完整的例子:
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;
}
}
分析結(jié)果
分析結(jié)果會(huì)根據(jù)指定格式輸出在指定文件目錄下。
圖形界面
檢測(cè)
D:\MyFile\Tool\pmd-bin-6.32.0\bin 目錄下打開(kāi)cmd窗口輸入:
cpdgui.bat

自定義規(guī)則

D:\MyFile\Tool\pmd-bin-6.32.0\bin 目錄下打開(kāi)cmd窗口輸入:
designer.bat

自定義規(guī)則:不能有變量為keafmd的String類型的變量
String keafmd; //這樣就是不合法的。
Source:
public class KeepingItSerious {
Delegator keafmd; // FieldDeclaration
public void method() {
String keafmd; // LocalVariableDeclaration
}
}
導(dǎo)出的自定義規(guī)則:
<rule name="myrule" language="java" message="不能有變量為keafmd的String類型的變量" class="net.sourceforge.pmd.lang.rule.XPathRule"> <description> 自定義規(guī)則 </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>
到此這篇關(guān)于Java 代碼檢查工具之PMD入門使用詳細(xì)教程的文章就介紹到這了,更多相關(guān)Java 代碼檢查工具PMD內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot 項(xiàng)目設(shè)置網(wǎng)站圖標(biāo)的方法
這篇文章主要介紹了Spring Boot 項(xiàng)目設(shè)置網(wǎng)站圖標(biāo)的方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-02-02
java實(shí)現(xiàn)KFC點(diǎn)餐小程序
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)KFC點(diǎn)餐系統(tǒng)小程序,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
java設(shè)計(jì)模式之觀察者模式簡(jiǎn)單解讀
這篇文章主要介紹了java設(shè)計(jì)模式之觀察者模式簡(jiǎn)單解讀,觀察者模式是在對(duì)象之間定義了一對(duì)多的依賴,這樣一來(lái),當(dāng)一個(gè)對(duì)象改變狀態(tài),依賴它的對(duì)象會(huì)收到通知并自動(dòng)更新,需要的朋友可以參考下2023-10-10
WMTS中TileMatrix與ScaleDenominator淺析
這篇文章主要為大家介紹了WMTS中TileMatrix與ScaleDenominator淺析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03
SpringCloud Alibaba使用Seata處理分布式事務(wù)的技巧
在傳統(tǒng)的單體項(xiàng)目中,我們使用@Transactional注解就能實(shí)現(xiàn)基本的ACID事務(wù)了,隨著微服務(wù)架構(gòu)的引入,需要對(duì)數(shù)據(jù)庫(kù)進(jìn)行分庫(kù)分表,每個(gè)服務(wù)擁有自己的數(shù)據(jù)庫(kù),這樣傳統(tǒng)的事務(wù)就不起作用了,那么我們?nèi)绾伪WC多個(gè)服務(wù)中數(shù)據(jù)的一致性呢?跟隨小編一起通過(guò)本文了解下吧2021-06-06
基于IDEA查看maven依賴結(jié)構(gòu)流程解析
這篇文章主要介紹了基于IDEA查看maven依賴結(jié)構(gòu)流程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09

