Awesome
gradle-errorprone-plugin
This plugin configures JavaCompile
tasks to use Error Prone.
Requirements
This plugin requires using at least Gradle 6.8.
While JDK 8 is supported, it is recommended to use at least a JDK 9 compiler. See note below about JDK 8 support.
There's no specific support for the Android Gradle Plugin. Read on to better understand what you need to do to use both plugins together. Specifically, note that source sets below are only about standard Gradle source sets for JVM projects, not Android source sets, so anything done by the plugin based on source sets won't be done at all for Android projects.
Usage
plugins {
id("net.ltgt.errorprone") version "<plugin version>"
}
This plugin creates a configuration named errorprone
,
and configures the <sourceSet>AnnotationProcessor
configuration for each source set to extend it.
This allows configuring Error Prone dependencies from a single place.
Error Prone needs to be added as a dependency in this configuration:
repositories {
mavenCentral()
}
dependencies {
errorprone("com.google.errorprone:error_prone_core:$errorproneVersion")
}
[!CAUTION] Using a dynamic or changing version for Error Prone, such as
latest.release
or2.+
, means that your build could fail at any time, if a new version of Error Prone adds or enables new checks that your code would trigger.
Error Prone can then be configured on the JavaCompile
tasks:
import net.ltgt.gradle.errorprone.errorprone
tasks.withType<JavaCompile>().configureEach {
options.errorprone.disableWarningsInGeneratedCode.set(true)
}
<details>
<summary>with Groovy DSL</summary>
tasks.withType(JavaCompile).configureEach {
options.errorprone.disableWarningsInGeneratedCode = true
}
</details>
and can also be disabled altogether:
tasks {
compileTestJava {
options.errorprone.isEnabled.set(false)
}
}
<details>
<summary>with Groovy DSL</summary>
tasks {
compileTestJava {
options.errorprone.enabled = false
}
}
</details>
Note that this plugin only enables Error Prone on tasks for source sets
(i.e. compileJava
for the main
source set, compileTestJava
for the test
source set,
and compileIntegTestJava
for a custom integTest
source set).
val annotationProcessorCustom = configurations.resolvable("annotationProcessorCustom") {
extendsFrom(configurations.errorprone.get())
}
tasks.register<JavaCompile>("compileCustom") {
source("src/custom/")
include("**/*.java")
classpath = configurations["custom"]
sourceCompatibility = "8"
targetCompatibility = "8"
destinationDir = file("$buildDir/classes/custom")
// Error Prone must be available in the annotation processor path
options.annotationProcessorPath = annotationProcessorCustom.get()
// Enable Error Prone
options.errorprone.isEnabled = true
// It can then be configured for the task
options.errorprone.disableWarningsInGeneratedCode = true
}
<details>
<summary>with Groovy DSL</summary>
def annotationProcessorCustom = configurations.resolvable("annotationProcessorCustom") {
extendsFrom(configurations.errorprone)
}
tasks.register("compileCustom", JavaCompile) {
source "src/custom/"
include "**/*.java"
classpath = configurations.custom
sourceCompatibility = "8"
targetCompatibility = "8"
destinationDir = file("$buildDir/classes/custom")
// Error Prone must be available in the annotation processor path
options.annotationProcessorPath = annotationProcessorCustom
// Enable Error Prone
options.errorprone.enabled = true
// It can then be configured for the task
options.errorprone.disableWarningsInGeneratedCode = true
}
</details>
</details>
JDK 8 support
Error Prone requires at least a JDK 9 compiler.
When using a JDK 8 compiler, the plugin will configure the JavaCompile
tasks to use a forking compiler
and will override the compiler by prepending the Error Prone javac to the bootstrap classpath
(using a -Xbootclasspath/p:
JVM argument).
You can configure JavaCompile
tasks to use a specific JDK compiler,
independently of the JDK used to run Gradle itself.
The plugin will use the toolchain version, if any is specified, to configure the task.
This allows you to enforce compilation with JDK 11 while running Gradle with JDK 8.
(In case you would want to enforce compilation with JDK 8 instead,
the plugin would detect it and properly configure the bootstrap classpath as described above)
Note that the plugin will ignore any task that forks and defines either a javaHome
or an executable
,
and thus won't configure the bootstrap classpath if you're e.g. running Gradle with a more recent JDK and forking the compilation tasks to use JDK 8.
JDK 16+ support
Starting with JDK 16, due to JEP 396: Strongly Encapsulate JDK Internals by Default,
--add-opens
and --add-exports
arguments need to be passed to the compiler's JVM.
The plugin will automatically use a forking compiler
and pass the necessary JVM arguments
whenever it detects such a JDK is being used and ErrorProne is enabled
(unless the Gradle daemon's JVM already was given the appropriate options through org.gradle.jvmargs
).
That detection will only take into account the toolchain used by the JavaCompile
task,
or the JDK used to run Gradle in case no toolchain is being used.
The plugin will ignore any task that forks and defines either a javaHome
or an executable
,
and thus won't configure the JVM arguments if you're e.g. running Gradle with an older JDK and forking the compilation tasks to use JDK 17.
Note that the plugin also configures the JVM arguments for any JDK above version 9 to silence related warnings, but they will then only be used if the task is explicitly configured for forking (or if the configured toolchain is incompatible with the JDK used to run Gradle, which will then implicitly fork a compiler daemon).
Android Gradle Plugin support
As noted above, this plugin won't have much effect when used in conjunction with the AGP rather than, say, Gradle's built-in Java plugins.
It will then:
- create the
errorprone
configuration, but won't wire it to any other configuration, and by extension to any compilation task - enhance
JavaCompile
tasks with theerrorprone
extension, but keep ErrorProne disabled by default (it would fail otherwise, as ErrorProne won't be on the processor path)
You'll thus have to somehow:
- put ErrorProne on the processor path of the
JavaCompile
tasks - enable ErrorProne on the
JavaCompile
tasks - configure
isCompilingTestOnlyCode
for compilation tasks for test variants (this changes the behavior of some checks)
This could (and should) be done by a plugin, so if you have deep knowledge of the AGP APIs and how to idiomatically integrate Error Prone within Android builds, please make such a plugin and I'll link to it here for others to use.
Custom Error Prone checks
Custom Error Prone checks can be added to the errorprone
configuration too:
dependencies {
errorprone("com.uber.nullaway:nullaway:$nullawayVersion")
}
or alternatively to the <sourceSet>AnnotationProcessor
configuration,
if they only need to be enabled for a given source set:
dependencies {
annotationProcessor("com.google.guava:guava-beta-checker:$betaCheckerVersion")
}
and can then be configured on the tasks; for example:
tasks.withType<JavaCompile>().configureEach {
options.errorprone {
option("NullAway:AnnotatedPackages", "net.ltgt")
}
}
tasks.compileJava {
// The check defaults to a warning, bump it up to an error for the main sources
options.errorprone.error("NullAway")
}
<details>
<summary>with Groovy DSL</summary>
tasks.withType(JavaCompile).configureEach {
options.errorprone {
option("NullAway:AnnotatedPackages", "net.ltgt")
}
}
tasks.compileJava {
// The check defaults to a warning, bump it up to an error for the main sources
options.errorprone.error("NullAway")
}
</details>
[!NOTE] These examples use NullAway. Note that I made a companion plugin specifically to surface NullAway options as Gradle DSL properties.
Configuration
As noted above, this plugin adds an errorprone
extension to the JavaCompile.options
.
It can be configured either as a property (options.errorprone.xxx
)
or script block (options.errorprone { … }
).
In a *.gradle.kts
script, the Kotlin extensions need to be imported:
import net.ltgt.gradle.errorprone.errorprone
Properties
Please note that all properties are lazy.
Property | Description |
---|---|
isEnabled | (enabled with Groovy DSL) Allows disabling Error Prone altogether for the task. Error Prone will still be in the annotation processor path, but -Xplugin:ErrorProne won't be passed as a compiler argument. Defaults to true for source set tasks, false otherwise. |
disableAllChecks | Disable all Error Prone checks; maps to -XepDisableAllChecks . This will be the first argument, so checks can then be re-enabled on a case-by-case basis. Defaults to false . |
disableAllWarnings | Maps to -XepDisableAllWarnings (since ErrorProne 2.4.0). Defaults to false . |
allErrorsAsWarnings | Maps to -XepAllErrorsAsWarnings . Defaults to false . |
allDisabledChecksAsWarnings | Enables all Error Prone checks, checks that are disabled by default are enabled as warnings; maps to -XepDisabledChecksAsWarnings . Defaults to false . |
disableWarningsInGeneratedCode | Disables warnings in classes annotated with javax.annotation.processing.Generated or @javax.annotation.Generated ; maps to -XepDisableWarningsInGeneratedCode . Defaults to false . |
ignoreUnknownCheckNames | Maps to -XepIgnoreUnknownCheckNames . Defaults to false . |
ignoreSuppressionAnnotations | Maps to -XepIgnoreSuppressionAnnotations (since Error Prone 2.3.3). Defaults to false . |
isCompilingTestOnlyCode | (compilingTestOnlyCode with Groovy DSL) Maps to -XepCompilingTestOnlyCode . Defaults to false . (defaults to true for a source set inferred as a test source set) |
excludedPaths | A regular expression pattern (as a string) of file paths to exclude from Error Prone checking; maps to -XepExcludedPaths . Defaults to null . |
checks | A map of check name to CheckSeverity , to configure which checks are enabled or disabled, and their severity; maps each entry to -Xep:<key>:<value> , or -Xep:<key> if the value is CheckSeverity.DEFAULT . Defaults to an empty map. |
checkOptions | A map of check options to their value; maps each entry to -XepOpt:<key>=<value> . Use an explicit "true" value for a boolean option. Defaults to an empty map. |
errorproneArgs | Additional arguments passed to Error Prone. Defaults to an empty list. |
errorproneArgumentProviders | A list of CommandLineArgumentProvider for additional arguments passed to Error Prone. Defaults to an empty list. |
Methods
Method | Description |
---|---|
enable(checkNames...) | Adds checks with their default severity. Useful in combination with disableAllChecks to selectively re-enable checks. Equivalent to check(checkName, CheckSeverity.DEFAULT) for each check name. |
disable(checkNames...) | Disable checks. Equivalent to check(checkName, CheckSeverity.OFF) for each check name. |
warn(checkNames...) | Adds checks with warning severity. Equivalent to check(checkName, CheckSeverity.WARNING) for each check name. |
error(checkNames...) | Adds checks with error severity. Equivalent to check(checkName, CheckSeverity.ERROR) for each check name. |
check(checkName to severity...) | (Kotlin DSL only) Adds pairs of check name to severity. Equivalent to checks.put(first, second) for each pair. |
check(checkName, severity) | Adds a check with a given severity. The severity can be passed as a provider for lazy configuration. Equivalent to checks.put(checkName, severity) . |
option(optionName) | Enables a boolean check option. Equivalent to option(checkName, true) . |
option(optionName, value) | Adds a check option with a given value. Value can be a boolean or a string, or a provider of string. Equivalent to checkOptions.put(name, value) . |
A check severity can take values: DEFAULT
, OFF
, WARN
, or ERROR
.
Note that the net.ltgt.gradle.errorprone.CheckSeverity
needs to be import
ed into your build scripts (see examples above).