介绍

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内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!