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. 官方文档
3. 社区优秀实践
3.1 Google 内部及 Google 开源项目
ErrorProne 由 Google 开发并在内部 Java 构建系统中大规模使用,是 Google 代码质量保障体系的核心工具之一。Google 多个知名开源项目在构建中集成了 ErrorProne。
- Google Guava:https://github.com/google/guava
- Google Auto(AutoValue/AutoService):https://github.com/google/auto
- Google Truth:https://github.com/google/truth
典型实践(以 Google Guava 为例):在 pom.xml 的 maven-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(如 AndroidInjectionBeforeSuper、MislabeledAndroidString、IsLoggableTagLength 等)专门针对 Android 开发场景设计。
- Android Open Source Project:https://android.googlesource.com/
典型实践:AOSP 在 Soong 构建系统中通过 java_plugin 规则加载 ErrorProne,对平台 Java/Kotlin 代码进行编译期 Bug 检测,与 Google 内部的 Java 编码规范保持一致。
3.3 Netflix
Netflix 大量使用 Java 技术栈,其开源的 Nebula Gradle 插件集提供了 ErrorProne 集成支持,帮助 Netflix 的微服务项目在构建阶段自动进行编译期 Bug 检测。
- Netflix Nebula:https://github.com/nebula-plugins
- Netflix OSS Gradle 插件:https://github.com/nebula-plugins/gradle-extra-configurations-plugin
典型实践:Netflix 项目通过 Gradle 构建系统集成 ErrorProne,配合 tbroyer/gradle-errorprone-plugin(https://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 可选:ERROR、WARNING、DEFAULT、OFF) |
-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-plugin 的 annotationProcessorPaths 机制集成。
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.xml 的 maven-compiler-plugin 的 compilerArgs 中传递 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 条目。