Skip to content

rules_jvm_external - Override remote jars

Published: at 04:00 PM

There are times where you are working on a Bazel project that is pulling in dependencies via rules_jvm_external and you may want to override a jar with a locally built one. This is useful when you want to test a change in a dependency that is not yet published.

Let’s see this in action. The code for this example can be found here. This post assumes you already have a Bazel project set up with rules_jvm_external.

Querying the Original Target

For the sake of this example, we will be replacing the guava jar with our own jar. Let’s query for the original guava target. Output trimmed for brevity. This will show the target that is being generated by rules_jvm_external, and we will use it in a subsequent step.

> bazel query @maven//... | grep guava
@maven//:com_google_guava_guava

> bazel query @maven//:com_google_guava_guava --output=build
jvm_import(
  name = "com_google_guava_guava",
  visibility = ["//visibility:public"],
  tags = ["maven_coordinates=com.google.guava:guava:32.0.1-jre", "maven_repository=https://repo1.maven.org/maven2", "maven_sha256=bd7fa227591fb8509677d0d1122cf95158f3b8a9f45653f58281d879f6dc48c5", "maven_url=https://repo1.maven.org/maven2/com/google/guava/guava/32.0.1-jre/guava-32.0.1-jre.jar"],
  jar = "@maven//:com/google/guava/guava/32.0.1-jre/guava-32.0.1-jre.jar",
  deps = ["@maven//:com_google_code_findbugs_jsr305", "@maven//:com_google_errorprone_error_prone_annotations", "@maven//:com_google_guava_failureaccess", "@maven//:com_google_guava_listenablefuture", "@maven//:com_google_j2objc_j2objc_annotations", "@maven//:org_checkerframework_checker_qual"],
  maven_coordinates = "com.google.guava:guava:32.0.1-jre",
  maven_url = "https://repo1.maven.org/maven2/com/google/guava/guava/32.0.1-jre/guava-32.0.1-jre.jar",
)

Creating the Override Target

Start by adding a maven.override to your MODULE.bazel file. This is telling rules_jvm_external to override whatever is in the maven_install.json file with the target specified.

I am using a target called my_guava in the override directory. You can name this whatever you want, but it should be a target that is not already in use.

# MODULE.bazel
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

maven.install(
    artifacts = [
        "com.google.guava:guava:31.0.1-jre",
    ],
    lock_file = "//:maven_install.json",
)

maven.override(
    coordinates = "com.google.guava:guava",
    target = "@//override:my_guava",
)

Now we are going to create the my_guava target. To make this simple, we will just copy the jvm_import rule that we queried for earlier and just change the jar attribute to point to a local jar.

The local jar can be copied from a remote maven repository, built from a java_library target, copied from your ~/.m2 directory, or whatever you want. In this example, I am just using an empty jar file.

# override/BUILD.bazel
load("@rules_jvm_external//private/rules:jvm_import.bzl", "jvm_import")

jvm_import(
    name = "my_guava",
    # This is a jar copied into the workspace
    jar = ":empty.jar",
    # This is a generated jar
    # jar = ":empty_bin_deploy.jar",
    # This is the original jar
    # jar = "@maven//:com/google/guava/guava/32.0.1-jre/guava-32.0.1-jre.jar",
    maven_coordinates = "com.google.guava:guava:32.0.1-jre",
    maven_url = "https://repo1.maven.org/maven2/com/google/guava/guava/32.0.1-jre/guava-32.0.1-jre.jar",
    tags = [
        "maven_coordinates=com.google.guava:guava:32.0.1-jre",
        "maven_repository=https://repo1.maven.org/maven2",
        "maven_sha256=bd7fa227591fb8509677d0d1122cf95158f3b8a9f45653f58281d879f6dc48c5",
        "maven_url=https://repo1.maven.org/maven2/com/google/guava/guava/32.0.1-jre/guava-32.0.1-jre.jar",
    ],
    visibility = ["//visibility:public"],
    deps = [
        "@maven//:com_google_code_findbugs_jsr305",
        "@maven//:com_google_errorprone_error_prone_annotations",
        "@maven//:com_google_guava_failureaccess",
        "@maven//:com_google_guava_listenablefuture",
        "@maven//:com_google_j2objc_j2objc_annotations",
        "@maven//:org_checkerframework_checker_qual",
    ],
)

Okay, now let’s query the target and see if it’s being overridden. Output trimmed for brevity.

> bazel query @maven//:com_google_guava_guava --output=build
alias(
  name = "com_google_guava_guava",
  visibility = ["//visibility:public"],
  actual = "//override:my_guava",
)

Success! Now, anywhere in your project where you are using @maven//:com_google_guava_guava, it will be replaced with the jar at //override:my_guava.

WORKSPACE

If you are still using WORKSPACE, overriding the targets is mostly the same. The only difference is that instead of using maven.override in the MODULE.bazel file, you will use the override_targets attribute on the maven_install rule in your WORKSPACE file.

maven_install(
    name = "maven",
    artifacts = [
        "com.google.guava:guava:31.0.1-jre",
    ],
    repositories = [
        "https://repo.maven.apache.org/maven2",
    ],
    override_targets = {
        "com.google.guava:guava": "//override:my_guava",
    },
)

The full bzlmod and WORKSPACE examples can be found here.


Next Post
Test Filtering with Ruff