Our goal is to make it simple to add Error Prone checks to your existing Java
compilation. Please note that Error Prone must be run on JDK 17 or newer. (It
can still be used to build Java 8 code by setting the appropriate -source
/
-target
/ -bootclasspath
flags.)
Please join our mailing list to know when a new version is released!
Error Prone works out of the box with Bazel.
java_library(
name = "hello",
srcs = ["Hello.java"],
)
$ bazel build :hello
ERROR: example/myproject/BUILD:29:1: Java compilation in rule '//example/myproject:hello'
examples/maven/error_prone_should_flag/src/main/java/Main.java:20: error: [DeadException] Exception created but not thrown
new Exception();
^
(see http://errorprone.info/bugpattern/DeadException)
Did you mean 'throw new Exception();'?
1 error
BazelJavaBuilder threw exception: java compilation returned status ERROR
INFO: Elapsed time: 1.989s, Critical Path: 1.69s
Edit your pom.xml
file to add settings to the maven-compiler-plugin:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>8</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-XDcompilePolicy=simple</arg>
<arg>--should-stop=ifError=FLOW</arg>
<arg>-Xplugin:ErrorProne</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>com.google.errorprone</groupId>
<artifactId>error_prone_core</artifactId>
<version>${error-prone.version}</version>
</path>
<!-- Other annotation processors go here.
If 'annotationProcessorPaths' is set, processors will no longer be
discovered on the regular -classpath; see also 'Using Error Prone
together with other annotation processors' below. -->
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
Additional flags are required due to JEP 396: Strongly Encapsulate JDK Internals by Default.
If your maven-compiler-plugin
uses an external executable, e.g. because
<fork>
is true
or because the maven-toolchains-plugin
is enabled, add the
following under compilerArgs
in the configuration above:
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED</arg>
<arg>-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED</arg>
<arg>-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED</arg>
Otherwise, add the following to the .mvn/jvm.config file:
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
See the flags documentation for details on how to customize the plugin’s behavior.
The gradle plugin is an external contribution. The documentation and code is at tbroyer/gradle-errorprone-plugin.
Download the following artifacts from maven:
error_prone_core-${EP_VERSION?}-with-dependencies.jar
from
https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/dataflow-errorprone-${DATAFLOW_VERSION?}.jar
from
https://repo1.maven.org/maven2/io/github/eisop/dataflow-errorprone/and add the following javac task to your project’s build.xml
file:
<path id="processorpath.ref">
<pathelement location="${user.home}/.m2/repository/com/google/errorprone/error_prone_core/${error-prone.version}/error_prone_core-${error-prone.version}-with-dependencies.jar"/>
<pathelement location="${user.home}/.m2/repository/io/github/eisop/dataflow-errorprone/${dataflow.version}/dataflow-errorprone-${dataflow.version}.jar"/>
</path>
<javac srcdir="src" destdir="build" fork="yes" includeantruntime="no">
<compilerarg value="-XDcompilePolicy=simple"/>
<compilerarg value="--should-stop=ifError=FLOW"/>
<compilerarg value="-processorpath"/>
<compilerarg pathref="processorpath.ref"/>
<compilerarg value="-Xplugin:ErrorProne -Xep:DeadException:ERROR" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED" />
<compilerarg value="-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED" />
<compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED" />
<compilerarg value="-J--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED" />
</javac>
Setting the following --add-exports=
flags is required on JDK 16 and newer due
to
JEP 396: Strongly Encapsulate JDK Internals by Default:
To add the plugin, start the IDE and find the Plugins dialog. Browse Repositories, choose Category: Build, and find the Error-prone plugin. Right-click and choose “Download and install”. The IDE will restart after you’ve exited these dialogs.
To enable Error Prone, choose Settings | Compiler | Java Compiler | Use
compiler: Javac with error-prone
and also make sure Settings | Compiler | Use
external build
is NOT selected.
Ideally, you should find out about failed Error Prone checks as you code in
eclipse, thanks to the continuous compilation by ECJ (eclipse compiler for
Java). But this is an architectural challenge, as Error Prone currently relies
heavily on the com.sun.*
APIs for accessing the AST and symbol table.
For now, Eclipse users should use the Findbugs eclipse plugin instead, as it catches many of the same issues.
Error Prone supports the
com.sun.source.util.Plugin
API, which can be used by adding Error Prone to the -processorpath
and setting
the -Xplugin
flag.
Example:
wget https://repo1.maven.org/maven2/com/google/errorprone/error_prone_core/${EP_VERSION?}/error_prone_core-${EP_VERSION?}-with-dependencies.jar
wget https://repo1.maven.org/maven2/io/github/eisop/dataflow-errorprone/${DATAFLOW_VERSION?}/dataflow-errorprone-${DATAFLOW_VERSION?}.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-${EP_VERSION?}-with-dependencies.jar:dataflow-errorprone-${DATAFLOW_VERSION?}.jar \
'-Xplugin:ErrorProne -XepDisableAllChecks -Xep:CollectionIncompatibleType:ERROR' \
ShortSet.java
ShortSet.java:8: error: [CollectionIncompatibleType] Argument 'i - 1' should not be passed to this method; its type int is not compatible with its collection's type argument Short
s.remove(i - 1);
^
(see http://errorprone.info/bugpattern/CollectionIncompatibleType)
1 error
The --add-exports
and --add-opens
flags are required due to
JEP 396: Strongly Encapsulate JDK Internals by Default:
If you’re an end-user of the build system, you can file a bug to request integration.
If you develop a build system, you should create an integration for your users! Here are some basics to get you started:
Error-prone is implemented as a compiler hook, using an internal mechanism in
javac. To install our hook, we override the main()
method in
com.sun.tools.javac.main.Main
.
Find the spot in your build system where javac’s main method is called. This is assuming you call javac in-process, rather than shell’ing out to the javac executable on the machine (which would be pretty lame since it’s hard to know where that’s located).
First, add Error Prone’s core library to the right classpath. It will need to be
visible to the classloader which currently locates the javac Main class. Then
replace the call of javac.main.Main.main()
with the Error Prone compiler:
return new ErrorProneCompiler.Builder().build().compile(args) == 0
All of the above instructions use the javac
option -processorpath
which has
side-effect of causing javac
to no longer scan the compile classpath for
annotation processors. If you are using other annotation processors in addition
to Error Prone, such as
AutoValue, then you will
need to add their JARs to your -processorpath
argument. The mechanics of this
will vary according to the build tool you are using.
(Compiling the Java 8 language level is still supported by using a javac from a
newer JDK, and setting the appropriate -source
/-target
/-bootclasspath
or
--release
flags).
For instructions on using Error Prone 2.10.0 with JDK 8, see this older version of the installation instructions.