PMD

← 返回目录 > ← 返回总览

相关工具推荐

工具 说明
Checkstyle Java 代码风格与规范检查工具,侧重命名、格式、Javadoc 等风格类检查
SpotBugs Java 字节码级缺陷检测工具,基于 Bug Patterns 发现潜在运行时问题
Google-Java-Format Google 出品的 Java 代码格式化工具,与 Google Java Style Guide 配合使用
Spotless 多语言代码格式化统一框架,支持 Maven/Gradle 集成

1. 简介

PMD 是一款开源的可扩展多语言静态代码分析工具,主要用于检测源代码中的潜在缺陷、不良编程实践和性能问题。PMD 通过 JavaCC 和 ANTLR 将源代码解析为抽象语法树(AST),然后对 AST 运行规则来发现违规。PMD 还内置了 CPD(Copy/Paste Detector)复制粘贴检测器,用于发现项目中的重复代码。

  • 主要检查语言:Java(核心)、Apex、Kotlin、Swift、JavaScript、PLSQL、Go、Python 等
  • 主要检查能力:检测未使用的变量、空 catch 块、不必要的对象创建、复杂代码等潜在问题;涵盖质量类检查(潜在缺陷、不良实践)、设计类检查(复杂度、耦合度)、安全类检查、性能类检查
  • 核心检查原理:基于 AST 分析,支持 XPath 和 Java 自定义规则
  • 检查规则/选项:规则按 Best Practices、Code Style、Design、Error Prone、Multithreading、Performance、Security 等 8 大类组织,数量随版本动态变化,Java 规则索引
  • GitHub 仓库https://github.com/pmd/pmd(5,422 stars)
  • 开源协议:BSD-2-Clause
  • 最新稳定版本:v7.11.0
  • 运行环境要求:PMD 7.x 需 Java 8+ 运行;Gradle PMD 插件需 Gradle 8.6+,Maven PMD 插件需 maven-pmd-plugin 3.22.0+
  • 误报率:中

2. 官方文档

资源 链接
官方网站 https://pmd.github.io/
在线文档(最新版) https://docs.pmd-code.org/latest/
安装与 CLI 使用 https://docs.pmd-code.org/latest/pmd_userdocs_installation.html
PMD CLI 参考 https://docs.pmd-code.org/latest/pmd_userdocs_cli_reference.html
规则集配置指南 https://docs.pmd-code.org/latest/pmd_userdocs_making_rulesets.html
规则配置详解 https://docs.pmd-code.org/latest/pmd_userdocs_configuring_rules.html
告警抑制方法 https://docs.pmd-code.org/latest/pmd_userdocs_suppressing_warnings.html
增量分析 https://docs.pmd-code.org/latest/pmd_userdocs_incremental_analysis.html
最佳实践 https://docs.pmd-code.org/latest/pmd_userdocs_best_practices.html
Java 规则参考 https://docs.pmd-code.org/latest/pmd_rules_java.html
CPD 文档 https://docs.pmd-code.org/latest/pmd_userdocs_cpd.html
PMD 7 迁移指南 https://docs.pmd-code.org/latest/pmd_userdocs_migrating_to_pmd7.html
Maven PMD 插件(PMD 官方文档) https://docs.pmd-code.org/latest/pmd_userdocs_tools_maven.html
Gradle PMD 插件(PMD 官方文档) https://docs.pmd-code.org/latest/pmd_userdocs_tools_gradle.html
Maven PMD 插件(Maven 官方) https://maven.apache.org/plugins/maven-pmd-plugin/
Gradle PMD 插件(Gradle 官方) https://docs.gradle.org/current/userguide/pmd_plugin.html
IDE 插件 https://docs.pmd-code.org/latest/pmd_userdocs_tools_ide_plugins.html
CI 集成 https://docs.pmd-code.org/latest/pmd_userdocs_tools_ci.html
GitHub 仓库 https://github.com/pmd/pmd
GitHub Releases https://github.com/pmd/pmd/releases

3. 社区优秀实践

3.1 Apache Maven 项目

Apache Maven 自身在父 POM 中配置了 PMD 插件,对所有 Maven 子模块执行静态代码分析检查。Maven 是 Java 构建工具的事实标准,其 PMD 配置是社区中最具参考价值的实践之一。

  • 仓库地址https://github.com/apache/maven
  • 配置特点:在 maven-parent 中统一管理 PMD 插件版本和规则集配置,子模块通过继承自动应用
  • 参考文件apache/maven/pom.xml 中的 maven-pmd-plugin 配置

3.2 Alibaba P3C(阿里巴巴 Java 编码规范)

阿里巴巴基于 PMD 实现了 P3C(Java 编码规范)规则集,这是国内 Java 社区使用最广泛的 PMD 规则集之一。P3C 规则集涵盖了阿里巴巴《Java 开发手册》中的所有编码规范,包括命名规约、OOP 规约、集合处理、并发处理、控制语句、异常处理等。

  • 仓库地址https://github.com/alibaba/p3c
  • 配置特点:提供了完整的 PMD 规则集实现和 IntelliJ IDEA / Eclipse 插件,支持 Maven 集成
  • 规则集文件p3c-pmd/src/main/resources/rulesets/java/ 目录下包含所有规则定义

3.3 Spring Framework

Spring Framework 作为 Java 生态中最流行的应用框架之一,在其构建流程中集成了 PMD 进行代码质量检查。Spring 项目的 PMD 配置代表了大型企业级 Java 项目的最佳实践。


4. 工具配置说明

4.1 配置文件说明

PMD 的规则集通过 XML 文件配置,这是 PMD 最核心的配置方式。规则集文件定义了要启用哪些规则、排除哪些规则以及规则的参数调整。

配置文件 格式 用途
ruleset.xml XML 规则集定义:引用规则分类、排除规则、覆盖规则属性、文件排除模式
pom.xml<pmdConfig> 节) XML Maven maven-pmd-plugin 中引用 ruleset.xml 并配置构建行为

规则集配置指南:https://docs.pmd-code.org/latest/pmd_userdocs_making_rulesets.html

4.2 ruleset.xml 配置详解

ruleset.xml 是 PMD 的主配置文件,通过引用规则分类、排除规则、覆盖属性来定制检查规则。

配置项说明

配置项 类型 说明
<ruleset name> string 规则集名称
<description> string 规则集描述
<rule ref> string 引用规则分类(如 category/java/bestpractices.xml)或单个规则(如 category/java/errorprone.xml/EmptyCatchBlock
<rule ref> 下的 <exclude name> string 从引用的分类中排除指定规则
<rule ref> 下的 <properties> map 覆盖规则属性,每项含 <property name value>
<exclude-pattern> string 文件排除正则,匹配的文件不参与检查

规则属性覆盖示例

通过 <properties> 节点覆盖单个规则的默认参数:

<!-- 覆盖 NPathComplexity 的报告级别阈值 -->
<rule ref="category/java/design.xml/NPathComplexity">
    <properties>
        <property name="reportLevel" value="200"/>
    </properties>
</rule>

推荐配置示例

以下是一个面向 Java 项目的推荐规则集配置,涵盖了最佳实践、代码风格、设计、错误倾向等核心类别。每条规则均附说明。

<?xml version="1.0"?>
<ruleset name="Recommended Java Rules"
         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
                             https://pmd.sourceforge.io/ruleset_2_0_0.xsd">

    <description>
        PMD 推荐规则集 - 适用于 Java 项目的综合代码质量检查配置。
        涵盖最佳实践、代码风格、设计、错误倾向等核心类别。
    </description>

    <!-- ============================================ -->
    <!-- Best Practices(最佳实践)                     -->
    <!-- ============================================ -->
    <rule ref="category/java/bestpractices.xml">
        <!-- 排除:JUnit 测试方法应为包级别访问(某些框架要求 public) -->
        <exclude name="JUnitJupiterTestShouldBePackagePrivate"/>
        <!-- 排除:JUnit5 测试不应为包级别(同上) -->
        <exclude name="JUnit5TestShouldBePackagePrivate"/>
    </rule>

    <!-- ============================================ -->
    <!-- Code Style(代码风格)                          -->
    <!-- ============================================ -->
    <rule ref="category/java/codestyle.xml">
        <!-- 排除:控制语句必须使用大括号(部分团队允许单行不加括号) -->
        <exclude name="ControlStatementBraces"/>
        <!-- 排除:短变量名(某些场景下短变量名更清晰) -->
        <exclude name="ShortVariable"/>
        <!-- 排除:长变量名(某些场景下需要描述性命名) -->
        <exclude name="LongVariable"/>
        <!-- 排除:方法命名约定(某些框架有特殊命名要求) -->
        <exclude name="MethodNamingConventions"/>
        <!-- 排除:局部变量命名约定 -->
        <exclude name="LocalVariableNamingConventions"/>
    </rule>

    <!-- ============================================ -->
    <!-- Design(设计)                                -->
    <!-- ============================================ -->
    <rule ref="category/java/design.xml">
        <!-- 排除:NPath 复杂度(与圈复杂度存在重叠) -->
        <exclude name="NPathComplexity"/>
        <!-- 排除:过多导入(某些大型项目需要较多导入) -->
        <exclude name="ExcessiveImports"/>
    </rule>

    <!-- ============================================ -->
    <!-- Error Prone(错误倾向)                        -->
    <!-- ============================================ -->
    <rule ref="category/java/errorprone.xml">
        <!-- 排除:空 catch 块(某些框架要求空 catch 块) -->
        <!-- 如需保留,可配置忽略特定异常类型 -->
    </rule>

    <!-- ============================================ -->
    <!-- Multithreading(多线程)                       -->
    <!-- ============================================ -->
    <rule ref="category/java/multithreading.xml">
        <!-- 仅保留关键的多线程规则 -->
        <exclude name="DoNotUseThreads"/>
    </rule>

    <!-- ============================================ -->
    <!-- Performance(性能)                            -->
    <!-- ============================================ -->
    <rule ref="category/java/performance.xml">
        <!-- 排除:避免在循环中实例化对象(某些场景需要) -->
        <exclude name="AvoidInstantiatingObjectsInLoops"/>
    </rule>

    <!-- ============================================ -->
    <!-- Security(安全)                              -->
    <!-- ============================================ -->
    <rule ref="category/java/security.xml"/>

    <!-- ============================================ -->
    <!-- 文件排除                                      -->
    <!-- ============================================ -->
    <!-- 排除自动生成的代码 -->
    <exclude-pattern>.*/generated/.*</exclude-pattern>
    <!-- 排除测试代码(如需单独配置测试规则) -->
    <!-- <exclude-pattern>.*/src/test/.*</exclude-pattern> -->

</ruleset>

快速开始规则集

PMD 提供了内置的快速开始规则集,适合新项目快速启用:

# 使用内置快速开始规则集
pmd check -d src/main/java -R rulesets/java/quickstart.xml -f text

rulesets/java/quickstart.xml 包含了 PMD 推荐的常用规则子集,适合作为初始配置的起点。

4.3 规则分类说明

PMD 将所有内置规则分为以下 8 个统一类别(从 6.0.0 开始):

类别 说明 规则集路径
Best Practices 强制执行普遍接受的最佳实践,如使用 equals() 比较字符串、正确关闭资源等 category/java/bestpractices.xml
Code Style 统一编码风格,包括命名约定、代码结构、大括号使用等 category/java/codestyle.xml
Design 发现设计问题,如过高的圈复杂度、过多的方法参数、God Class 等 category/java/design.xml
Documentation 确保代码文档的完整性,如类和方法注释 category/java/documentation.xml
Error Prone 检测容易出错、令人困惑或可能导致运行时错误的代码结构 category/java/errorprone.xml
Multithreading 标记多线程环境中潜在的问题,如不安全的同步、死锁风险等 category/java/multithreading.xml
Performance 标记可能导致性能问题的次优代码,如不必要的对象创建 category/java/performance.xml
Security 标记潜在的安全漏洞 category/java/security.xml

4.4 第三方规则集

规则集 说明 链接
Alibaba P3C 阿里巴巴 Java 编码规范 PMD 实现,国内使用最广泛 https://github.com/alibaba/p3c

Java 规则完整参考:https://docs.pmd-code.org/latest/pmd_rules_java.html


5. 主流集成方式

5.1 Maven 集成(生态主流,优先)

Maven 是 Java 生态中最主流的构建工具,maven-pmd-plugin 是 PMD 最推荐的集成方式。当前 Maven PMD 插件默认使用 PMD 7.x(maven-pmd-plugin 3.22.0+)。

<properties>
    <pmd.version>7.25.0</pmd.version>
    <maven-pmd-plugin.version>3.26.0</maven-pmd-plugin.version>
</properties>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-pmd-plugin</artifactId>
                <version>${maven-pmd-plugin.version}</version>
                <dependencies>
                    <dependency>
                        <groupId>net.sourceforge.pmd</groupId>
                        <artifactId>pmd-core</artifactId>
                        <version>${pmd.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>net.sourceforge.pmd</groupId>
                        <artifactId>pmd-java</artifactId>
                        <version>${pmd.version}</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </pluginManagement>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-pmd-plugin</artifactId>
            <configuration>
                <!-- 规则集配置 -->
                <rulesets>
                    <ruleset>${project.basedir}/config/pmd/ruleset.xml</ruleset>
                </rulesets>
                <!-- 源代码编码 -->
                <sourceEncoding>UTF-8</sourceEncoding>
                <!-- 目标 JDK 版本 -->
                <targetJdk>${maven.compiler.target}</targetJdk>
                <!-- 排除生成的代码 -->
                <excludeRoots>
                    <excludeRoot>target/generated-sources</excludeRoot>
                </excludeRoots>
                <!-- 输出目录 -->
                <outputDirectory>${project.build.directory}/pmd-report</outputDirectory>
                <!-- 是否在违规时失败 -->
                <failOnViolation>true</failOnViolation>
                <!-- 打印失败错误 -->
                <printFailingErrors>true</printFailingErrors>
                <!-- 失败优先级(1-5,1最严重) -->
                <failurePriority>3</failurePriority>
                <!-- 启用增量分析 -->
                <analysisCache>true</analysisCache>
            </configuration>
            <executions>
                <execution>
                    <id>pmd-check</id>
                    <phase>verify</phase>
                    <goals>
                        <goal>check</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

常用 Maven 命令:

# 生成 PMD 报告(不中断构建)
mvn pmd:pmd

# 执行 PMD 检查(违规时中断构建)
mvn pmd:check

# 执行 CPD 重复代码检测
mvn pmd:cpd

# 跳过 PMD 检查
mvn verify -Dpmd.skip=true

Maven PMD 插件文档:https://maven.apache.org/plugins/maven-pmd-plugin/

增量检查:在 pom.xml 中启用增量分析(maven-pmd-plugin 3.8+ 支持),通过缓存分析数据跳过未修改文件。

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-pmd-plugin</artifactId>
    <configuration>
        <!-- 启用增量分析 -->
        <analysisCache>true</analysisCache>
        <!-- 可选:指定缓存文件位置(默认如下) -->
        <analysisCacheLocation>${project.build.directory}/pmd/pmd.cache</analysisCacheLocation>
    </configuration>
</plugin>

5.2 pre-commit 集成

PMD 分析 Java 源代码,pre-commit hook 依赖本地 JDK 和构建工具链。

注意:以下配置使用 language: system,依赖本地已安装的 JDK 和 Maven/Gradle,执行环境需要预先完成项目编译。

repos:
  - repo: local
    hooks:
      - id: pmd-check
        name: PMD Static Analysis
        entry: bash -c 'mvn pmd:check -q'
        language: system
        types: [java]
        pass_filenames: false

安装钩子:

pip install pre-commit
pre-commit install

说明pass_filenames: false 表示不将变更文件列表传给 hook,因为 PMD 通过 Maven 插件管理分析范围。language: system 要求本地环境已安装 JDK 和 Maven。

增量检查:pre-commit 框架默认只对暂存区中变更的 .java 文件触发 hook。由于 PMD 的 local hook 使用 pass_filenames: false(让 Maven 自行管理检查范围),实际增量由 Maven 构建 + PMD 的 --cache 缓存机制决定。pre-commit 负责"何时触发"(只在有 .java 文件变更时),PMD 的 --cache 缓存负责"加速检查"(跳过未修改文件)。CI 中可通过 pre-commit run --all-files 做全量检查。

# .pre-commit-config.yaml(增量推荐配置)
- repo: local
  hooks:
    - id: pmd-check
      name: PMD check
      entry: mvn pmd:check
      language: system
      files: \.java$
      pass_filenames: false # 由 Maven + PMD --cache 控制增量

5.3 IDE 集成

VS Code

安装 PMD for Java 扩展:

  1. 打开 VS Code,进入扩展市场
  2. 搜索 "PMD for Java" 并安装
  3. 在项目根目录创建 .vscode/settings.json
{
  "pmd.ruleset": "config/pmd/ruleset.xml",
  "pmd.executable": "path/to/pmd-bin-7.25.0/bin/pmd",
  "pmd.jdkVersion": "17"
}

IntelliJ IDEA

安装 PMDPMD X 插件:

  1. 打开 Settings > Plugins,搜索 "PMD" 并安装
  2. 配置 PMD:Settings > Other Settings > PMD
  3. 指定 PMD 安装路径和规则集文件路径
  4. 右键点击代码目录或文件,选择 Run PMD 执行检查

PMD IDE 插件文档:https://docs.pmd-code.org/latest/pmd_userdocs_tools_ide_plugins.html

5.4 命令行使用方式

安装

# Linux / macOS
curl -OL https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.25.0/pmd-dist-7.25.0-bin.zip
unzip pmd-dist-7.25.0-bin.zip
# 添加到 PATH
export PATH=$PATH:$HOME/pmd-bin-7.25.0/bin

# Windows (手动)
# 下载并解压到 C:\pmd-bin-7.25.0
# 将 C:\pmd-bin-7.25.0\bin 添加到 PATH

pmd check -- 代码分析

# 基本用法:分析源代码目录
pmd check -d src/main/java -R rulesets/java/quickstart.xml -f text

# 使用自定义规则集
pmd check -d src/main/java -R config/pmd/ruleset.xml -f html

# 指定语言版本
pmd check -d src/main/java -R rulesets/java/quickstart.xml --use-version java-17

# 输出格式:text / html / xml / json / csv / sarif
pmd check -d src/main/java -R rulesets/java/quickstart.xml -f sarif -o pmd-report.sarif

# 排除特定文件(PMD 7.14.0+)
pmd check -d src/main/java -R rulesets/java/quickstart.xml --exclude "src/main/java/generated/**"

# 指定最低优先级(1最严重,5最不严重)
pmd check -d src/main/java -R rulesets/java/quickstart.xml --minimum-priority 3

# 启用增量分析缓存
pmd check -d src/main/java -R rulesets/java/quickstart.xml --cache .pmdcache

# 禁用增量分析(全量扫描)
pmd check -d src/main/java -R rulesets/java/quickstart.xml --no-cache

# 指定辅助类路径(用于类型解析)
pmd check -d src/main/java -R rulesets/java/quickstart.xml --aux-classpath "lib/*:target/classes"

# 多线程分析(使用 2 个线程)
pmd check -d src/main/java -R rulesets/java/quickstart.xml -t 2

pmd cpd -- 复制粘贴检测

# 检测重复代码(默认最少 100 个 token)
pmd cpd -d src/main/java --minimum-tokens 100 -f text

# 指定语言
pmd cpd -d src/main/java --language java --minimum-tokens 50 -f xml

# 输出 HTML 格式报告
pmd cpd -d src/main/java --minimum-tokens 100 -f html -o cpd-report.html

# 同时检测多个目录
pmd cpd -d src/main/java:src/test/java --minimum-tokens 100 -f text

其他子命令

# 启动 PMD 规则设计器(GUI,需要 JavaFX)
pmd designer

# 启动 CPD GUI
pmd cpd-gui

# 查看版本
pmd --version

# 查看帮助
pmd check --help
pmd cpd --help

PMD CLI 参考文档:https://docs.pmd-code.org/latest/pmd_userdocs_cli_reference.html

增量检查:PMD 命令行原生支持 --cache 参数实现增量分析,也支持基于 Git 的命令行增量方案。

--cache 参数(增量分析)

# 首次运行(全量分析,生成缓存)
pmd check -d src/main/java -R ruleset.xml -f text --cache .pmd-cache

# 后续运行(增量分析,跳过未修改文件)
pmd check -d src/main/java -R ruleset.xml -f text --cache .pmd-cache

PMD 缓存默认存储在用户临时目录,可通过 --cache 参数指定缓存文件路径。缓存文件记录了每个文件的分析结果和最后修改时间,下次运行时自动跳过未修改的文件。

缓存失效条件

以下情况会导致缓存失效,PMD 将重新分析所有文件:

  1. 规则集变更:修改了 ruleset.xml 或引用的规则集
  2. PMD 版本升级:不同版本的 PMD 缓存不兼容
  3. 文件被删除:缓存中记录的文件被删除会触发缓存更新
  4. 文件内容变更:文件被修改(通过文件最后修改时间和内容哈希判断)

官方文档PMD Incremental Analysis

基于 Git 的命令行增量方案

# 获取变更的 Java 文件列表并分析
git diff --name-only --diff-filter=ACMR HEAD -- '*.java' | xargs pmd check -R ruleset.xml -f text

# 仅分析暂存区的 Java 文件
git diff --name-only --cached -- '*.java' | xargs pmd check -R ruleset.xml -f text

注意:此方案仅分析变更文件本身,不分析依赖这些文件的其他文件。PMD 的静态分析通常不依赖跨文件分析(每个文件独立分析),因此此方案比 Mypy 等类型检查工具更适合文件级增量。

CI 脚本调用

GitHub Actions

.github/workflows/pmd-check.yml 中配置:

name: PMD Code Check

on: [push, pull_request]

permissions:
  contents: read

jobs:
  pmd-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Set up JDK 17
        uses: actions/setup-java@v4
        with:
          distribution: "temurin"
          java-version: "17"

      - name: Cache Maven dependencies
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
          restore-keys: |
            ${{ runner.os }}-maven-

      - name: Run PMD Check
        run: mvn pmd:check -Dpmd.skip=false

      - name: Upload PMD Report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: pmd-report
          path: target/pmd-report/

GitLab CI

.gitlab-ci.yml 中配置:

pmd-check:
  stage: test
  image: maven:3.9-eclipse-temurin-17
  script:
    - mvn pmd:check -B
  artifacts:
    when: always
    paths:
      - target/pmd-report/
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
    - if: '$CI_COMMIT_BRANCH == "main"'

增量检查:CI/CD 场景下可利用 PMD 的 --cache 参数或 Maven 的 analysisCache 实现增量分析。

GitHub Actions(增量:使用 --cache)

name: PMD Check (Incremental)
on: [push, pull_request]

jobs:
  pmd:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: "21"
          distribution: "temurin"

      - name: Cache PMD results
        uses: actions/cache@v4
        with:
          path: .pmd-cache
          key: pmd-${{ runner.os }}-${{ hashFiles('**/*.java') }}

      - name: Run PMD with incremental cache
        run: |
          wget -q https://github.com/pmd/pmd/releases/download/pmd_releases%2F7.16.0/pmd-dist-7.16.0-bin.zip
          unzip -q pmd-dist-7.16.0-bin.zip
          ./pmd-bin-7.16.0/bin/pmd check -d src/main/java -R ruleset.xml -f text --cache .pmd-cache

GitLab CI(增量:使用 Maven analysisCache)

# .gitlab-ci.yml
pmd-check:
  image: maven:3.9-eclipse-temurin-21
  script:
    - mvn pmd:check -DanalysisCache=true
  cache:
    paths:
      - target/pmd/pmd.cache
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

5.5 Gradle 集成

Gradle 内置了 PMD 插件,开箱即用。使用 PMD 7 需要 Gradle 8.6+。

// build.gradle
plugins {
    id 'pmd'
}

pmd {
    // PMD 版本(PMD 7 需要 Gradle 8.6+)
    toolVersion = "7.25.0"
    // 使用自定义规则集文件(推荐)
    ruleSetFiles = files("config/pmd/ruleset.xml")
    // 清空默认规则集,避免与自定义规则集冲突
    ruleSets = []
    // 是否忽略失败(true=不中断构建,false=违规时中断构建)
    ignoreFailures = false
    // 报告输出目录
    reportsDir = file("${buildDir}/reports/pmd")
}

Kotlin DSL 写法:

// build.gradle.kts
plugins {
    pmd
}

pmd {
    toolVersion = "7.25.0"
    ruleSetFiles = files("config/pmd/ruleset.xml")
    ruleSets = emptyList()
    isIgnoreFailures = false
}

常用 Gradle 命令:

# 对 main 源码执行 PMD 检查
./gradlew pmdMain

# 对 test 源码执行 PMD 检查
./gradlew pmdTest

# 执行所有 PMD 检查
./gradlew pmd

Gradle PMD 插件文档:https://docs.gradle.org/current/userguide/pmd_plugin.html

增量检查:Gradle PMD 插件默认支持增量任务(Gradle 的 up-to-date 检查),只需确保使用 ./gradlew pmdMain 而非 --rerun-tasks,Gradle 会自动处理增量(仅重新分析变更的文件)。

6. 告警抑制(屏蔽)方法

PMD 提供了多种告警抑制方法,从代码级别到规则集级别均可控制。官方文档:https://docs.pmd-code.org/latest/pmd_userdocs_suppressing_warnings.html

6.1 通过代码屏蔽

@SuppressWarnings 注解(推荐)

在 Java 代码中使用注解抑制特定规则或所有 PMD 警告:

// 抑制类中所有 PMD 警告
@SuppressWarnings("PMD")
public class MyClass {
    // ...
}

// 抑制特定规则
@SuppressWarnings("PMD.UnusedLocalVariable")
public void myMethod() {
    int x = 10; // 不会报 UnusedLocalVariable 警告
}

// 抑制多个规则
@SuppressWarnings({"PMD.UnusedLocalVariable", "PMD.UnusedPrivateMethod"})
public void myMethod() {
    // ...
}

// JDK 标准注解也会被 PMD 识别,抑制 unused 规则集中的所有规则
@SuppressWarnings("unused")
public class Bar {
    void bar() {
        int foo;       // 抑制 UnusedLocalVariable
    }
    private void foobar(){} // 抑制 UnusedPrivateMethod
}

官方文档参考:https://docs.pmd-code.org/latest/pmd_userdocs_suppressing_warnings.html#annotations

NOPMD 注释标记

在代码行末尾添加 // NOPMD 注释来抑制该行的警告:

public class Bar {
    // 'bar' 由本地方法访问,需要抑制警告
    private int bar; // NOPMD

    public void foo() {
        try {
            someMethod();
        } catch (FileNotFoundException e) {} // NOPMD - 此异常实际上不会发生
    }
}

注意// NOPMD 标记必须与违规代码在同一行。例如,要抑制空 if 语句的警告,需要将 // NOPMD 放在包含 if 关键字的行。

也可以通过 --suppress-marker 选项自定义抑制标记:

pmd check -d Foo.java -R category/java/bestpractices.xml --suppress-marker TURN_OFF_WARNINGS

官方文档参考:https://docs.pmd-code.org/latest/pmd_userdocs_suppressing_warnings.html#nopmd-comment

6.2 通过工具配置文件屏蔽

violationSuppressRegex(正则表达式抑制)

在规则集 XML 中,通过正则表达式匹配违规消息来抑制特定场景的警告:

<!-- 抑制特定参数名未使用的警告 -->
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter">
    <properties>
        <property name="violationSuppressRegex"
                  value=".*'mySpecialParameterName'.*"/>
    </properties>
</rule>

<!-- 抑制特定消息模式的警告 -->
<rule ref="category/java/design.xml/CyclomaticComplexity">
    <properties>
        <property name="violationSuppressRegex"
                  value=".*in class.*Service.*"/>
    </properties>
</rule>

官方文档参考:https://docs.pmd-code.org/latest/pmd_userdocs_suppressing_warnings.html#the-property-violationsuppressregex

violationSuppressXPath(XPath 抑制)

在规则集 XML 中,通过 XPath 表达式匹配 AST 节点来抑制特定代码结构的警告:

<!-- 抑制特定方法中的警告 -->
<rule ref="category/java/bestpractices.xml/UnusedFormalParameter">
    <properties>
        <property name="violationSuppressXPath"
                  value="./ancestor-or-self::MethodDeclaration[@Name='mySpecialMethod']"/>
    </properties>
</rule>

<!-- 抑制名称包含 Bean 的类中的警告 -->
<rule ref="category/java/design.xml/TooManyMethods">
    <properties>
        <property name="violationSuppressXPath"
                  value="./ancestor-or-self::ClassDeclaration[contains(@SimpleName, 'Bean')]"/>
    </properties>
</rule>

官方文档参考:https://docs.pmd-code.org/latest/pmd_userdocs_suppressing_warnings.html#the-property-violationsuppressxpath

规则集级别排除

在规则集 XML 中直接排除不需要的规则或文件:

<!-- 排除整个规则分类中的特定规则 -->
<rule ref="category/java/codestyle.xml">
    <exclude name="ShortVariable"/>
    <exclude name="LongVariable"/>
    <exclude name="ShortMethodName"/>
</rule>

<!-- 通过文件模式排除特定文件 -->
<exclude-pattern>.*/generated/.*</exclude-pattern>
<exclude-pattern>.*/model/.*</exclude-pattern>
<exclude-pattern>.*/\.*/.*</exclude-pattern>

规则集配置指南:https://docs.pmd-code.org/latest/pmd_userdocs_making_rulesets.html

6.3 通过工具命令行参数屏蔽

# 排除特定文件(PMD 7.14.0+)
pmd check -d src/main/java -R rulesets/java/quickstart.xml --exclude "src/main/java/generated/**"

# 通过排除文件列表排除(PMD 7.14.0+)
pmd check -d src/main/java -R rulesets/java/quickstart.xml --exclude-file-list exclude-list.txt

# 指定最低优先级(屏蔽低优先级告警)
pmd check -d src/main/java -R rulesets/java/quickstart.xml --minimum-priority 3

# 自定义抑制标记
pmd check -d src/main/java -R rulesets/java/quickstart.xml --suppress-marker TURN_OFF_WARNINGS

PMD CLI 参考:https://docs.pmd-code.org/latest/pmd_userdocs_cli_reference.html

6.4 通过集成调度工具屏蔽

Maven excludes 配置

通过 maven-pmd-pluginexcludeRootsincludes/excludes 参数排除特定文件或目录:

<configuration>
    <excludeRoots>
        <excludeRoot>target/generated-sources</excludeRoot>
    </excludeRoots>
    <includes>
        <include>**/*.java</include>
    </includes>
    <excludes>
        <exclude>**/generated/**</exclude>
    </excludes>
</configuration>

Maven PMD 插件文档:https://maven.apache.org/plugins/maven-pmd-plugin/

Gradle exclude 配置

pmd {
    ruleSetFiles = files("config/pmd/ruleset.xml")
    ruleSets = []
    exclude = ['**/generated/**', '**/model/**']
}

Gradle PMD 插件文档:https://docs.gradle.org/current/userguide/pmd_plugin.html

6.5 查找未使用的抑制

PMD 7.14.0 起提供了 UnnecessaryWarningSuppression 规则,用于发现未使用的 @SuppressWarnings("PMD.xxx")// NOPMD 注释:

<rule ref="category/java/bestpractices.xml/UnnecessaryWarningSuppression"/>

6.6 告警抑制方法总结

方法 粒度 适用场景 是否需要修改代码 官方文档
@SuppressWarnings("PMD.xxx") 类/方法/字段 已确认的误报或可接受的例外 Annotations
// NOPMD 单行 临时抑制特定行的告警 NOPMD comment
violationSuppressRegex 规则实例 通过消息正则匹配批量抑制 Regex suppression
violationSuppressXPath AST 节点 通过 XPath 精确匹配代码结构抑制 XPath suppression
规则集 <exclude> 规则级别 排除不需要的规则 Making rulesets
<exclude-pattern> 文件/目录 排除特定文件或目录 Making rulesets
CLI --exclude 文件/目录 临时排除特定路径 CLI reference
CLI --minimum-priority 优先级级别 屏蔽低优先级告警 CLI reference
Maven excludeRoots 目录 排除生成代码目录 Maven plugin
UnnecessaryWarningSuppression 抑制标记 清理过时的抑制注释 Rule reference

← 返回目录 > ← 返回总览