1. 概述

简单来说,PMD 是一个源代码分析器,用于查找诸如未使用的变量、空的catch块、不必要的对象创建等常见的编程缺陷。

它支持Java、JavaScript、Salesforce.com Apex、PLSQL、Apache Velocity、XML和XSL。

在这篇文章中,我们将重点介绍如何在Java项目中使用PMD进行静态分析。

2. 预备知识

首先,让我们在Maven项目中设置PMD - 使用并配置maven-pmd-plugin

<project>
    ...
    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-pmd-plugin</artifactId>
                <version>3.21.0</version>
                <configuration>
                    <rulesets>
                        <ruleset>/rulesets/java/braces.xml</ruleset>
                        <ruleset>/rulesets/java/naming.xml</ruleset>
                    </rulesets>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
</project>

您可以在这里找到maven-pmd-plugin的最新版本。

请注意我们在配置中添加了规则集 - 这是相对于PMD核心库中已经定义的规则的相对路径。

最后,在运行所有内容之前,让我们创建一个简单的Java类,其中包含一些明显的错误 - 这样PMD就可以开始报告问题了:

public class Ct {

    public int d(int a, int b) {
        if (b == 0)
            return Integer.MAX_VALUE;
        else
            return a / b;
    }
}

3. 运行PMD

有了简单的PMD配置和示例代码,让我们在构建目标文件夹中生成报告:

mvn site

生成的报告名为pmd.html,位于target/site文件夹中:

Files

com/baeldung/pmd/Cnt.java

Violation                                                                             Line

Avoid short class names like Cnt                                   1–10 
Avoid using short method names                                  3 
Avoid variables with short names like b                        3 
Avoid variables with short names like a                        3 
Avoid using if...else statements without curly braces 5 
Avoid using if...else statements without curly braces 7 

如您所见,我们没有得到结果。 报告根据PMD显示您的Java代码中的违规行为和行号。

4. 规则集

PMD插件使用五个默认规则集:

  • basic.xml
  • empty.xml
  • imports.xml
  • unnecessary.xml
  • unusedcode.xml

您可以使用其他规则集或创建自己的规则集,并在插件中进行配置:

<project>
    ...
    <reporting>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-pmd-plugin</artifactId>
                <version>3.21.0</version>
                <configuration>
                    <rulesets>
                        <ruleset>/rulesets/java/braces.xml</ruleset>
                        <ruleset>/rulesets/java/naming.xml</ruleset>
                        <ruleset>/usr/pmd/rulesets/strings.xml</ruleset>
                        <ruleset>http://localhost/design.xml</ruleset>
                    </rulesets>
                </configuration>
            </plugin>
        </plugins>
    </reporting>
</project>

请注意,我们使用相对地址、绝对地址甚至URL作为配置中ruleset值的值。

为项目自定义要使用的规则的一个干净策略是编写自定义规则集文件。在这个文件中,我们可以定义要使用的规则,添加自定义规则,并定制哪些规则应包括或排除在官方规则集中。

5. 自定义规则集

现在,让我们从PMD现有的规则集中选择要使用的特定规则,并对其进行定制。

首先,我们将创建一个新的ruleset.xml文件。当然,我们可以使用现有的规则集文件作为例子,将其复制到新文件中,删除所有旧规则,然后更改名称和描述:

<?xml version="1.0"?>
<ruleset name="Custom ruleset"
  xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0
  http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
    <description>
        This ruleset checks my code for bad stuff
    </description>
</ruleset>

其次,让我们添加一些规则引用:

<!-- We'll use the entire 'strings' ruleset -->
<rule ref="rulesets/java/strings.xml"/>

或者添加一些特定规则:

<rule ref="rulesets/java/unusedcode.xml/UnusedLocalVariable"/>
<rule ref="rulesets/java/unusedcode.xml/UnusedPrivateField"/>
<rule ref="rulesets/java/imports.xml/DuplicateImports"/>
<rule ref="rulesets/java/basic.xml/UnnecessaryConversionTemporary"/>

我们可以定制规则的消息和优先级:

<rule ref="rulesets/java/basic.xml/EmptyCatchBlock"
  message="Must handle exceptions">
    <priority>2</priority>
</rule>

您还可以像这样定制规则的属性值:

<rule ref="rulesets/java/codesize.xml/CyclomaticComplexity">
    <properties>
        <property name="reportLevel" value="5"/>
    </properties>
</rule>

请注意,您可以在自定义规则集中定制引用规则的几乎所有内容,除了规则的类。

接下来,您也可以从规则集中排除规则

<rule ref="rulesets/java/braces.xml">
    <exclude name="WhileLoopsMustUseBraces"/>
    <exclude name="IfElseStmtsMustUseBraces"/>
</rule>

此外,您还可以根据排除模式从规则集中排除文件**,可以有可选的覆盖包含模式。

当匹配到排除模式但没有匹配的包含模式时,文件将被排除在处理之外。

源文件路径中的路径分隔符会被标准化为'/'字符,因此同一个规则集可以在多个平台上透明地使用。

此外,这种排除/包含技术在如何使用PMD(例如命令行、IDE、Ant)的情况下都适用,使得在整个环境中保持PMD规则应用的一致性更加容易。

这里有一个快速示例:

<?xml version="1.0"?>
<ruleset ...>
    <description>My ruleset</description>
    <exclude-pattern>.*/some/package/.*</exclude-pattern>
    <exclude-pattern>
       .*/some/other/package/FunkyClassNamePrefix.*
    </exclude-pattern>
    <include-pattern>.*/some/package/ButNotThisClass.*</include-pattern>
    <rule>...
</ruleset>

6. 总结

在这篇简短的文章中,我们介绍了PMD - 一个灵活且高度可配置的工具,专注于Java代码的静态分析。

如往常一样,本教程中展示的完整代码可在GitHub上获取。


« 上一篇: Nashorn介绍
» 下一篇: Spring性能日志记录