Installation

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!

Bazel

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

Maven

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.

Gradle

The gradle plugin is an external contribution. The documentation and code is at tbroyer/gradle-errorprone-plugin.

Ant

Download the following artifacts from maven:

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:

IntelliJ IDEA

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.

Eclipse

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.

Command Line

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:

My build system isn’t listed here

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

Using Error Prone together with other annotation processors

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.

Running Error Prone on earlier JDK versions

  • Error Prone 2.10.0 is the latest version to support running on JDK 8.
  • Error Prone 2.31.0 is the latest version to support running on JDK 11.

(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.