org.apache.maven.plugins
maven-pmd-plugin
3.14.0
mvn 命令执行
在项目目录打开cmd窗口,输入以下命令:
mvn pmd:pmd
分析结果为pmd.html
文件,在项目的target下的site目录下:
分析结果显示内容:
pmd -d 源代码路径 -f xml(结果输出格式) -r 结果保存所在目录及名称 -R rulesets/java/unusedcode.xml
例子:
结果存放在制定文件目录下,格式也为命令语句指定的:
检测结果内容:
需要先引入maven依赖
项目结构
测试代码
Test01:
package com.keafmd.test01;
/**
-
Keafmd
-
@ClassName: Test01
-
@Description: 测试1
-
@author: 牛哄哄的柯南
-
@Date: 2021-03-15 15:29
-
@Blog: https://keafmd.blog.youkuaiyun.com/
*/
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.youkuaiyun.com/
*/
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.youkuaiyun.com/
*/
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.youkuaiyun.com/
*/
public class PmdExample {
public static void main(String[] args) {
/*String fileName ;
// 重新生成文件名(根据具体情况生成对应文件名)
fileName = UUID.randomUUID()+“_”+“pmd-report.html”;
PMDConfiguration configuration = new PMDConfiguration();
configuration.setInputPaths(“D:/file”);
configuration.setRuleSets(“rulesets/java/quickstart.xml”);
configuration.setReportFormat(“html”);
configuration.setReportFile(“D:/pmdreport/”+fileName);
PMD.doPMD(configuration);*/
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 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 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 determineFiles(String basePath) throws IOException {
Path dirPath = FileSystems.getDefault().getPath(basePath);
PathMatcher matcher = FileSystems.getDefault().getPathMatcher(“glob:*.java”);
List files = new ArrayList<>();
Files.walkFileTree(dirPath, new SimpleFileVisitor
@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: