Java 代码检查工具之PMD入门使用详细教程

网友投稿 499 2022-10-30


Java 代码检查工具之PMD入门使用详细教程

介绍

PMD是一个静态源代码分析器。它发现了常见的编程缺陷,如未使用的变量、空捕获块、不必要的对象创建等等。

官网:点这里

官方文档:点这里

使用方式

1、使用插件的方式

下载:File -> Settings -> Plugins -> Marketplace 搜索 “PMDPlugin” ,下载插件。

使用方法:在代码编辑框或Project 窗口的文件夹、包、文件右键,选择“Run PMD”->“Pre Defined”->“All”,对指定的文件夹、包、文件进行分析,分析结果在控制台输出。

2、maven项目引入依赖的方式

pom.xml:

xmlns:xsi="http://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">

4.0.0

com.keafmd

pdm-test01

1.0-SNAPSHOT

org.apache.maven.plugins

maven-pmd-plugin

3.14.0

xmlns:xsi="http://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">

4.0.0

com.keafmd

pdm-test01

1.0-SNAPSHOT

org.apache.maven.plugins

maven-pmd-plugin

3.14.0

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) {

mJLbm 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

*

* mJLbm@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 files = Arrays.asList(new FileDataSource(new File("/path/to/src/MyClass.java")));

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 rendererOutpmJLbmut = 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:

public class KeepingItSerious {

Delegator keafmd; // FieldDeclaration

public void method() {

String keafmd; // LocalVariableDeclaration

}

}

导出的自定义规则:

language="java"

message="不能有变量为keafmd的String类型的变量"

class="net.sourceforge.pmd.lang.rule.XPathRule">

自定义规则

3

<![CDATA[

//VariableDeclaratorId[@Image = "keafmd" and ../../Type[@TypeImage = "String"]]

]]>

language="java"

message="不能有变量为keafmd的String类型的变量"

class="net.sourceforge.pmd.lang.rule.XPathRule">

自定义规则

3

<![CDATA[

//VariableDeclaratorId[@Image = "keafmd" and ../../Type[@TypeImage = "String"]]

]]>


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:grep常见选项及命令
下一篇:【51CTO学院三周年】-亦大的小白菜网工历程
相关文章

 发表评论

暂时没有评论,来抢沙发吧~