Feat: Support pluggable Error Prone plugins via java_package_configuration
- Dominant language
- Java
- Stars
- 25.8k
- Forks
- 4.6k
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 72
Description
### Description
Currently, there is no clean, public-facing API in Bazel or `@bazel_tools` to compile a custom `JavaBuilder` binary with extra Error Prone plugins/checkers (e.g., custom checks fetched from Maven) and use it in a custom `java_toolchain`. Extending the default `JavaBuilder` requires knowledge of internal Bazel targets, private dependencies (like `@io_bazel//third_party`), and complex packaging/merging logic.
This proposal introduces a clean, public-facing Starlark API exposed under `@bazel_tools//tools/jdk:javabuilder.bzl` that allows clients to easily define custom `JavaBuilder` binaries and Error Prone check suites.
### Prerequisite: Move JavaBuilder to `rules_java`
Currently, the source code for the `JavaBuilder` compiler wrapper resides in the Bazel repository under `src/java_tools/buildjar/`. To enable clean customization of JavaBuilder and its dependencies from Starlark, `JavaBuilder` should be migrated to the `rules_java` repository first.
#### Required Changes:
1. **Bazel Repository**:
- Remove `src/java_tools/buildjar/` from the source tree.
- Update `tools/BUILD` (`embedded_tools_srcs`) to remove JavaBuilder source filegroups.
- Update `scripts/bootstrap/BUILD.bootstrap` to reference `@rules_java//java_tools/buildjar:bootstrap_VanillaJavaBuilder_deploy.jar` and `@rules_java//java_tools/buildjar:bootstrap_genclass_deploy.jar`.
- Remove the `java_tools` packaging targets from `src/BUILD` (as release archives will be built by `rules_java`).
2. **`rules_java` Repository**:
- Import the `src/java_tools/buildjar/` directory and configure its BUILD targets.
- Resolve its external dependencies (e.g. Guava, AutoValue, JSR305) using `rules_java`'s module/workspace dependencies.
- Expose the Starlark APIs (`default_javabuilder`, `errorprone_with_custom_plugins`) from `rules_java` directly.
- Set up release pipelines to build and package `java_tools.zip` for distribution.
### Proposed API Changes
We introduce two new public-facing rules/macros in `@bazel_tools//tools/jdk:javabuilder.bzl`:
1. `default_javabuilder`: A macro that packages a `JavaBuilder` executable. The default vanilla `JavaBuilder` is built by passing the default third-party Error Prone core libraries, while custom configurations can pass custom merged Error Prone engines.
2. `errorprone_with_custom_plugins`: A rule that merges a base Error Prone library (e.g. core Error Prone fetched from Maven) with custom checkers/plugins.
```starlark
load("@bazel_tools//tools/jdk:javabuilder.bzl", "default_javabuilder", "errorprone_with_custom_plugins")
load("@rules_java//toolchains:default_java_toolchain.bzl", "DEFAULT_TOOLCHAIN_CONFIGURATION", "default_java_toolchain")
# 1. Merge core Error Prone with a custom plugin
errorprone_with_custom_plugins(
name = "my_errorprone",
errorprone = "@maven//:com_google_errorprone_error_prone_core",
plugins = [":my_plugin"],
)
# 2. Build the custom JavaBuilder deploy jar
default_javabuilder(
name = "custom_javabuilder",
errorprone = [":my_errorprone"],
)
# 3. Associate it with a custom java_toolchain
default_java_toolchain(
name = "custom_toolchain",
configuration = DEFAULT_TOOLCHAIN_CONFIGURATION,
javabuilder = ":custom_javabuilder_deploy.jar",
)
```
> [!NOTE]
> **Package-Level Configuration**: Once a custom `JavaBuilder` is registered with the toolchain, users can configure the activation, severity, and options of these custom checkers on a package-by-package basis using the existing `java_package_configuration` API's `javacopts` attribute (e.g. passing `"-Xep:CustomCheck:ERROR"` for strict packages and `"-Xep:CustomCheck:OFF"` for legacy packages).
### Implementation Overview & Expected Diffs
#### 1. Bazel Core Diffs
* **API & Refactored JavaBuilder Targets** (`src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD`):
```diff
+java_library(
+ name = "javabuilder_errorprone_api",
+ srcs = ["javac/plugins/errorprone/ErrorProneInvoker.java"],
+ visibility = ["//visibility:public"],
+)
+
java_library(
- name = "buildjar",
- srcs = glob(["**/*.java"]),
- deps = ["//third_party:error_prone", ...],
+ name = "javabuilder_without_errorprone",
+ srcs = glob(
+ ["**/*.java"],
+ exclude = ["javac/plugins/errorprone/ErrorProneInvokerImpl.java"],
+ ),
+ deps = [
+ ":javabuilder_errorprone_api",
+ # other non-errorprone dependencies
+ ],
)
```
* **ServiceLoader Hook** in JavaBuilder:
```diff
+ServiceLoader loader = ServiceLoader.load(ErrorProneInvoker.class);
+Iterator iterator = loader.iterator();
+if (iterator.hasNext()) {
+ ErrorProneInvoker invoker = iterator.next();
+ invoker.init(context);
+}
```
* **Export API & Base targets in `@bazel_tools`** (`tools/BUILD`):
```diff
filegroup(
name = "embedded_tools_srcs",
srcs = [
...
+ "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:javabuilder_errorprone_api",
+ "//src/java_tools/buildjar/java/com/google/devtools/build/buildjar:javabuilder_without_errorprone",
...
],
)
```
#### 2. `rules_java` Diffs
* **Assemble JavaBuilder via `default_javabuilder`** (`toolchains/default_java_toolchain.bzl`):
```diff
+load("@bazel_tools//tools/jdk:javabuilder.bzl", "default_javabuilder")
def default_java_toolchain(name, ...):
+ default_javabuilder(
+ name = name + "_javabuilder",
+ errorprone = ["@rules_java//third_party:error_prone"],
+ )
+
native.java_toolchain(
name = name,
- javabuilder = ["@bazel_tools//tools/jdk:JavaBuilder_deploy.jar"],
+ javabuilder = [":" + name + "_javabuilder_deploy.jar"],
...
)
```
Contributor guide
Research direction
Start by reading the JavaBuilder sources under src/java_tools/buildjar/ and the related targets in src/BUILD, tools/BUILD, and scripts/bootstrap/BUILD.bootstrap. Then inspect rules_java's toolchains/default_java_toolchain.bzl and its dependency configuration. Done means JavaBuilder can be migrated and packaged through the proposed public Starlark APIs, with custom Error Prone plugins usable in a java_toolchain.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- build-system
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100