Skip to content

Feat: Support pluggable Error Prone plugins via java_package_configuration #1

Description

@JonathanPerry651

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.

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.
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):
    +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:
    +ServiceLoader<ErrorProneInvoker> loader = ServiceLoader.load(ErrorProneInvoker.class);
    +Iterator<ErrorProneInvoker> iterator = loader.iterator();
    +if (iterator.hasNext()) {
    +    ErrorProneInvoker invoker = iterator.next();
    +    invoker.init(context);
    +}
  • Export API & Base targets in @bazel_tools (tools/BUILD):
     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):
    +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"],
             ...
         )

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions