ErrorProne

← 返回目录 > ← 返回总览

相关工具推荐

工具 说明
Checkstyle Java 代码风格和编码规范检查
SpotBugs Java 字节码级缺陷检测
PMD Java AST 级静态分析和代码质量检查
Google-Java-Format Google Java 代码格式化工具

1. 简介

ErrorProne 是 Google 开源的 Java 静态分析工具,作为 javac 编译器插件在编译期运行,可捕获常见编程错误和 API 误用。与传统的字节码分析工具(如 SpotBugs)不同,ErrorProne 直接在编译器 AST 层面工作,无需额外的分析步骤。开发者在日常编译时即可获得即时反馈,无需改变现有工作流。

  • 主要检查语言:Java
  • 主要检查能力:在 Java 编译期捕获常见编程错误(集合类型不匹配、空指针风险、字符串比较反转、日期时间 API 误用等);涵盖质量类检查(编译期 Bug 检测和 API 误用发现)
  • 核心检查原理:基于 Java 编译器 AST 的编译期分析,通过插件机制在编译流程中注入检查
  • 检查规则/选项:bug pattern 按"On by default: ERROR"、"On by default: WARNING"、"Experimental"三类组织,数量随版本动态变化,全量 bug pattern 列表
  • GitHub 仓库https://github.com/google/error-prone(5,700 stars)
  • 开源协议:Apache-2.0
  • 最新稳定版本:v2.50.0
  • 运行环境要求:需 JDK 21+ 运行;可通过 -source/-target/--release 编译 Java 8 代码。2.42.0 是最后支持 JDK 17 的版本,2.31.0 是最后支持 JDK 11 的版本
  • 误报率:低

2. 官方文档

资源 链接 说明
官方网站 https://errorprone.info/ 项目主页,包含概览和快速入门
安装指南 https://errorprone.info/docs/installation Maven/Gradle/Bazel/Ant/命令行/IDE 安装配置
命令行标志文档 https://errorprone.info/docs/flags 所有 -Xep* 命令行参数、配置文件、严重级别说明
Bug Pattern 列表 https://errorprone.info/bugpatterns 全部 500+ 检查规则的详细说明,按严重级别分类
代码自动修复(Patching) https://errorprone.info/docs/patching 使用 -XepPatchChecks / -XepPatchLocation 自动修复代码
Refaster 规则 https://errorprone.info/docs/refaster 使用 Before/After 模板编写自定义重构规则
自定义插件开发 https://errorprone.info/docs/plugins 编写自定义 BugChecker 插件的完整指南
@InlineMe 注解 https://errorprone.info/docs/inlineme 使用 @InlineMe 标记可内联的 API 迁移
新检查规则标准 https://errorprone.info/docs/criteria ErrorProne 接受新检查规则的评判标准
Javadoc API https://errorprone.info/api/latest/ ErrorProne 公开 API 的 Javadoc 文档
GitHub 仓库 https://github.com/google/error-prone 源代码、Issue 追踪、Release 下载
GitHub Releases https://github.com/google/error-prone/releases 版本发布记录与变更日志
开发者 Wiki https://github.com/google/error-prone/wiki/For-Developers ErrorProne 开发者构建与贡献指南
邮件列表(讨论) https://groups.google.com/forum/#!forum/error-prone-discuss 社区讨论组
邮件列表(公告) https://groups.google.com/forum/#!forum/error-prone-announce 版本发布公告

3. 社区优秀实践

3.1 Google 内部及 Google 开源项目

ErrorProne 由 Google 开发并在内部 Java 构建系统中大规模使用,是 Google 代码质量保障体系的核心工具之一。Google 多个知名开源项目在构建中集成了 ErrorProne。

典型实践(以 Google Guava 为例):在 pom.xmlmaven-compiler-plugin 中配置 -Xplugin:ErrorProne,使用 -XepDisableAllWarnings 关闭所有警告级检查,仅保留 ERROR 级别规则,并按需关闭特定检查(如 -Xep:NullArgumentForNonNullParameter:OFF)。Guava 使用 ErrorProne v2.47.0,通过 annotationProcessorPaths 加载 error_prone_core

<!-- Google Guava 的 maven-compiler-plugin 配置片段 -->
<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <compilerArgs combine.children="override">
      <arg>-XDcompilePolicy=simple</arg>
      <arg>--should-stop=ifError=FLOW</arg>
      <arg>-Xplugin:ErrorProne -Xep:NullArgumentForNonNullParameter:OFF
        -Xep:Java8ApiChecker:ERROR -XepDisableAllWarnings</arg>
    </compilerArgs>
    <annotationProcessorPaths>
      <path>
        <groupId>com.google.errorprone</groupId>
        <artifactId>error_prone_core</artifactId>
        <version>${error_prone_core.version}</version>
      </path>
    </annotationProcessorPaths>
    <fork>true</fork>
  </configuration>
</plugin>

3.2 Android Open Source Project

Android 开源项目(AOSP)在平台 Java 代码的构建流程中集成了 ErrorProne,利用其 Soong 构建系统中的 errorprone 编译器插件对框架层 Java 代码进行编译期检查。ErrorProne 的部分 Bug Pattern(如 AndroidInjectionBeforeSuperMislabeledAndroidStringIsLoggableTagLength 等)专门针对 Android 开发场景设计。

典型实践:AOSP 在 Soong 构建系统中通过 java_plugin 规则加载 ErrorProne,对平台 Java/Kotlin 代码进行编译期 Bug 检测,与 Google 内部的 Java 编码规范保持一致。

3.3 Netflix

Netflix 大量使用 Java 技术栈,其开源的 Nebula Gradle 插件集提供了 ErrorProne 集成支持,帮助 Netflix 的微服务项目在构建阶段自动进行编译期 Bug 检测。

典型实践:Netflix 项目通过 Gradle 构建系统集成 ErrorProne,配合 tbroyer/gradle-errorprone-pluginhttps://github.com/tbroyer/gradle-errorprone-plugin)在编译期自动运行 ErrorProne 检查,将 ERROR 级别问题作为构建失败条件。


4. 工具配置说明

4.1 配置文件说明

ErrorProne 支持通过命令行参数或 errorprone.cfg 配置文件进行配置,所有通过 -Xplugin:ErrorProne 传递的 -Xep* 参数都可以写入配置文件。

配置方式 用途 使用场景
errorprone.cfg -Xep* 参数写入文件,通过 @ 语法加载 需要共享或版本控制配置的项目
命令行参数(-Xep: / -XepPatchChecks: 直接传递给 javac 的检查参数 命令行编译或简单项目
构建工具插件参数 通过 Maven/Gradle/Bazel 插件传递参数 集成到构建流程的项目(详见第5章)

4.2 ErrorProne 配置详解

配置项说明

配置项 类型 说明
-Xep:<CheckName>[:Severity] string 启用/禁用/调整特定检查的严重级别(Severity 可选:ERRORWARNINGDEFAULTOFF
-XepPatchChecks:<CheckList> string 启用自动修复的检查列表
-XepPatchInput:<filePath> string 应用补丁的基础文件路径
-XepPatchOutput:<filePath> string 补丁输出文件路径
-XepDisableWarningsInGeneratedCode flag 禁用生成代码中的警告
-XepExcludedPaths:<regex> string 排除匹配正则的文件路径
-XepAllSuggestionsAsWarnings flag 将所有建议转为警告
-XepAllDisabledChecksAsWarnings flag 启用所有已禁用的检查作为警告
-XepIgnoreUnknownCheckNames flag 忽略未知的检查名称

errorprone.cfg 文件格式

errorprone.cfg 是一个 properties 格式文件,每行一个 -Xep* 参数,支持 # 注释:

# 全局设置
-XepAllErrorsAsWarnings
-XepDisableWarningsInGeneratedCode

# 关闭特定检查
-Xep:JavaUtilDate:OFF
-Xep:JUnit4TestNotRun:OFF

# 调整检查级别
-Xep:MisusedWeekYear:WARN
-Xep:MisusedDayOfYear:WARN

# 排除路径
-XepExcludedPaths:.*/build/generated/.*

# 注释支持(# 开头为注释)
# -Xep:SomeCheck:OFF

使用方式

# 命令行
javac ... '-Xplugin:ErrorProne @/path/to/errorprone.cfg'

推荐配置示例

方案一:基础 Java 项目推荐配置

适用于大多数 Java 项目的入门配置,启用 ErrorProne 默认 ERROR 级别检查,关闭生成代码中的警告,并按需调整个别检查。

errorprone.cfg

# 关闭生成代码中的警告
-XepDisableWarningsInGeneratedCode

# 关闭在旧代码库中常见的误报检查
-Xep:JavaUtilDate:OFF
-Xep:JavadocMethod:OFF
-Xep:MethodCanBeStatic:OFF

# 将部分建议级检查降级为警告(不阻断构建)
-Xep:FutureReturnValueIgnored:WARN
-Xep:Immutable:WARN
-Xep:AnnotateMethodWithOverride:WARN

# 排除生成代码目录
-XepExcludedPaths:.*/build/generated/.*|.*/generated-sources/.*

方案二:Google 推荐配置(严格模式)

Google 内部使用 ErrorProne 的严格模式,将所有 ERROR 级别检查作为编译错误,并启用额外的实验性检查。适合追求高代码质量的新项目。参考 Google Java Error Prone 配置指南

errorprone.cfg

# 严格模式:所有错误级检查阻断构建
-XepDisableWarningsInGeneratedCode

# 启用所有实验性检查作为警告
-XepAllDisabledChecksAsWarnings

# 关闭不适合当前项目的检查(按需调整)
# -Xep:SomeExperimentalCheck:OFF

注意:-Xep:All:ERROR 会将所有 ErrorProne 检查设为 ERROR 级别,包括所有默认的 WARNING 和 ERROR 检查。适用于对代码质量有严格要求的项目。

5. 主流集成方式

5.1 Maven 集成(推荐优先)

Maven 是 Java 生态中最主流的构建工具,ErrorProne 通过 maven-compiler-pluginannotationProcessorPaths 机制集成。

pom.xml 配置示例

<properties>
  <error-prone.version>2.50.0</error-prone.version>
  <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
</properties>

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>${maven-compiler-plugin.version}</version>
      <configuration>
        <source>17</source>
        <target>17</target>
        <encoding>UTF-8</encoding>
        <compilerArgs>
          <arg>-XDcompilePolicy=simple</arg>
          <arg>--should-stop=ifError=FLOW</arg>
          <arg>-Xplugin:ErrorProne</arg>
          <!-- JDK 21+ 需要以下参数 -->
          <arg>-XDaddTypeAnnotationsToSymbol=true</arg>
        </compilerArgs>
        <annotationProcessorPaths>
          <path>
            <groupId>com.google.errorprone</groupId>
            <artifactId>error_prone_core</artifactId>
            <version>${error-prone.version}</version>
          </path>
          <!-- 其他注解处理器也需放在此处 -->
        </annotationProcessorPaths>
      </configuration>
    </plugin>
  </plugins>
</build>

注意:由于 JEP 396(JDK 16+ 强封装 JDK 内部 API),还需要在 .mvn/jvm.config 文件中添加 --add-exports--add-opens 参数,详见安装指南

传递 ErrorProne 标志

<arg>-Xplugin:ErrorProne -Xep:DeadException:WARN -Xep:GuardedBy:OFF</arg>

或使用配置文件(推荐):

<arg>-Xplugin:ErrorProne @${project.basedir}/errorprone.cfg</arg>

增量检查:Maven 和 Gradle 的增量编译机制会自动传递给 ErrorProne:

# Maven 增量编译(默认行为,仅编译变更的源文件)
mvn compile

# Gradle 增量编译(默认行为,通过 task up-to-date 检查)
./gradlew compileJava

5.2 IDE 集成

IntelliJ IDEA

在 Plugins 对话框中搜索 "Error-prone" 插件(Category: Build),下载安装后,进入 Settings | Compiler | Java Compiler,选择 Use compiler: Javac with error-prone,并确保 Settings | Compiler | Use external build 未被选中。

Eclipse

ErrorProne 当前依赖 com.sun.* 内部 API,与 Eclipse 的 ECJ 编译器不兼容。Eclipse 用户建议使用 SpotBugs 替代。

5.3 命令行使用

ErrorProne 通过 javac 的 -Xplugin 机制运行,支持 com.sun.source.util.Plugin API。

# 下载依赖
wget https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/2.50.0/error_prone_core-2.50.0-with-dependencies.jar
wget https://repo1.maven.org/maven2/io/github/eisop/dataflow-errorprone/2.50.0/dataflow-errorprone-2.50.0.jar

# 运行检查
javac \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
  -J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
  -J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
  -J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
  -XDcompilePolicy=simple \
  --should-stop=ifError=FLOW \
  -processorpath error_prone_core-2.50.0-with-dependencies.jar:dataflow-errorprone-2.50.0.jar \
  '-Xplugin:ErrorProne' \
  ShortSet.java

自动修复模式

# 生成 patch 文件
javac ... '-Xplugin:ErrorProne -XepPatchChecks:MissingOverride,DefaultCharset,DeadException -XepPatchLocation:/path/to/source'

# 直接原地修复
javac ... '-Xplugin:ErrorProne -XepPatchChecks:MissingOverride,DefaultCharset -XepPatchLocation:IN_PLACE'

增量检查 -- 对于需要显式控制检查范围的场景,可以结合 git diff 筛选变更文件:

# 仅检查 Git 变更的 Java 文件
git diff --name-only --diff-filter=ACMR -- '*.java' | \
  xargs javac \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
    -J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
    -J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED \
    -J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED \
    -XDcompilePolicy=simple \
    --should-stop=ifError=FLOW \
    -processorpath error_prone_core-2.50.0-with-dependencies.jar:dataflow-errorprone-2.50.0.jar \
    '-Xplugin:ErrorProne' \
    -sourcepath src/main/java \
    -classpath "$(mvn dependency:build-classpath -q -DincludeScope=compile -Dmdep.outputFile=/dev/stdout)"

CI 脚本调用

GitHub Actions 示例

name: Java CI with ErrorProne

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          java-version: "21"
          distribution: "temurin"
      - name: Build with ErrorProne
        run: mvn compile -B
        # ErrorProne 作为 javac 插件在编译时自动运行

GitLab CI 示例

build:
  image: maven:3.9-eclipse-temurin-21
  script:
    - mvn compile -B
  # ErrorProne 作为 javac 插件在编译时自动运行

增量检查:ErrorProne 是 javac 编译器插件,在编译过程中运行,不能脱离编译器独立执行,不适合放入 pre-commit 提交前检查。建议在本地通过 mvn compile./gradlew compileJava 触发 ErrorProne 检查,或在 PR 门禁的编译阶段中执行。

增量检查(CI/CD) -- GitHub Actions 增量检查示例:

name: ErrorProne Check
on: [pull_request]
jobs:
  errorprone:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: "21"
          distribution: "temurin"
      - name: Run ErrorProne on changed files
        run: |
          FILES=$(git diff --name-only --diff-filter=ACMR origin/${{ github.base_ref }}...HEAD | grep '\.java$')
          if [ -n "$FILES" ]; then
            mvn compile -Derrorprone.args="-Xep:All:ERROR"
          else
            echo "No Java files changed, skipping ErrorProne check."
          fi

说明:ErrorProne 的增量检查能力来自 javac 编译器本身。在 CI 中,由于通常是全量编译(无本地缓存),ErrorProne 会检查所有源文件。如需 CI 中也实现增量检查,可使用 Maven Incremental Build 工具或在 CI 中缓存编译产物。

5.4 Gradle 集成

Gradle 集成通过第三方插件 tbroyer/gradle-errorprone-plugin 实现。

build.gradle.kts 配置示例

plugins {
    id("net.ltgt.errorprone") version "5.1.0"
}

repositories {
    mavenCentral()
}

dependencies {
    errorprone("com.google.errorprone:error_prone_core:2.50.0")
}

tasks.withType<JavaCompile>().configureEach {
    options.errorprone.disableWarningsInGeneratedCode = true
}

build.gradle(Groovy DSL)配置示例

plugins {
    id 'net.ltgt.errorprone' version '5.1.0'
}

dependencies {
    errorprone 'com.google.errorprone:error_prone_core:2.50.0'
}

tasks.withType(JavaCompile).configureEach {
    options.errorprone.disableWarningsInGeneratedCode = true
}

5.5 Bazel 集成

ErrorProne 在 Bazel 中开箱即用,无需额外配置。Bazel 的 Java 编译规则默认支持 ErrorProne。

# BUILD
java_library(
    name = "hello",
    srcs = ["Hello.java"],
)

执行 bazel build :hello 即自动运行 ErrorProne 检查。

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

6.1 通过代码注解屏蔽(@SuppressWarnings)

使用 Java 标准的 @SuppressWarnings 注解,配合 ErrorProne 的 Bug Pattern 名称屏蔽特定检查。

// 屏蔽单个检查
@SuppressWarnings("CollectionIncompatibleType")
public void foo() {
    Set<Short> s = new HashSet<>();
    s.remove(0); // int 不兼容 Short
}

// 屏蔽多个检查
@SuppressWarnings({"DeadException", "ReferenceEquality"})
public void bar() {
    new Exception(); // 不会报 DeadException
}

注意@SuppressWarnings 的值应使用 Bug Pattern 的名称(如 CollectionIncompatibleType),而非检查类名。完整的 Bug Pattern 名称列表见 Bug Pattern 列表

6.2 通过命令行参数屏蔽

使用 -Xep:<checkName>[:severity] 参数控制检查的启用/禁用和严重级别。

# 关闭特定检查
-Xep:GuardedBy:OFF

# 将检查降级为警告
-Xep:DeadException:WARN

# 将检查升级为错误
-Xep:ReferenceEquality:ERROR

# 关闭所有检查,再按需开启
-XepDisableAllChecks -Xep:CollectionIncompatibleType:ERROR -Xep:DeadException:ERROR

# 关闭所有警告级检查
-XepDisableAllWarnings

# 将所有错误降级为警告
-XepAllErrorsAsWarnings

# 排除特定路径
-XepExcludedPaths:.*/build/generated/.*

详细参数说明见命令行标志文档

6.3 通过配置文件屏蔽

所有 -Xep* 参数都可以写入配置文件,便于在 Maven/Gradle/命令行之间共享。

# errorprone.cfg
-XepDisableWarningsInGeneratedCode
-Xep:JavaUtilDate:OFF
-Xep:GuardedBy:OFF
-XepExcludedPaths:.*/build/generated/.*

配置文件说明见命令行标志文档 - Configuration file

6.4 通过 Maven 配置屏蔽

pom.xmlmaven-compiler-plugincompilerArgs 中传递 ErrorProne 标志。

<plugin>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <showWarnings>true</showWarnings>
    <compilerArgs>
      <arg>-XDcompilePolicy=simple</arg>
      <arg>--should-stop=ifError=FLOW</arg>
      <arg>-Xplugin:ErrorProne -Xep:DeadException:WARN -Xep:GuardedBy:OFF</arg>
    </compilerArgs>
  </configuration>
</plugin>

Maven 传递标志的详细说明见命令行标志文档 - Maven

6.5 通过 Gradle 配置屏蔽

使用 net.ltgt.errorprone 插件的 DSL 进行配置。

// build.gradle.kts
tasks.withType<JavaCompile>().configureEach {
    options.errorprone {
        disableWarningsInGeneratedCode = true
        disable("GuardedBy", "JavaUtilDate")
        check("DeadException", CheckSeverity.WARN)
        excludedPaths = ".*/build/generated/.*"
    }
}
// build.gradle
tasks.withType(JavaCompile).configureEach {
    options.errorprone {
        disableWarningsInGeneratedCode = true
        disable 'GuardedBy', 'JavaUtilDate'
        check 'DeadException', CheckSeverity.WARN
        excludedPaths = '.*/build/generated/.*'
    }
}

6.6 屏蔽生成代码中的警告

使用 -XepDisableWarningsInGeneratedCode 标志,自动跳过带有 @Generated 注解的类中的所有警告。

# 命令行
-XepDisableWarningsInGeneratedCode

# Maven
<arg>-Xplugin:ErrorProne -XepDisableWarningsInGeneratedCode</arg>

# Gradle
options.errorprone.disableWarningsInGeneratedCode = true

说明见命令行标志文档中的 -XepDisableWarningsInGeneratedCode 条目。