javabazel

bazel build issue - either com.sun.tools.javac or var keyword causes a failure


TL:DR;

With the default java language versions, the var keyword causes errors, but specifying version 11 results in references to com.sun.tools.javac.* causing errors.

See the Minimal Example

The Long Version

Versions of things:

Background: I've recently migrated to bzlmod and got the basics working with a local registry. I wanted to try my hand at a custom errorprone BugChecker, which meant expanding my registry's errorprone module to include the check_api directory tree in addition to just the annotations.

After fighting with other dependencies, I was able to find the maven additions I'd need for the module, but ran into one last issue I can't figure out how to resolve:

The code under this directory references com.sun.tools.javac.* and also uses the var keyword. If I don't specify java language versions in my .bazelrc, the var keyword causes the error:

warning: as of release 10, 'var' is a restricted type name \
  and cannot be used for type declarations or as the element type of an array

Which I found confusing at first as I thought the default language level was now 11, but I was wrong. So this is expected.

But when I specify a higher language level by adding build --java_language_version=11 --tool_java_language_version=11 to my bazelrc then the com.sun.tools.javac references cause the error:

error: package com.sun.tools.javac.code is not visible
import com.sun.tools.javac.code.Symbol.ClassSymbol;
                          ^
  (package com.sun.tools.javac.code is declared in module jdk.compiler, which does not export it to the unnamed module)

What makes this especially confusing is that when this happens bazel indicates that the full command is:

external\rules_java~~toolchains~remotejdk21_win\bin\java.exe \
    --add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
    --add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED \
    ... (remaining 19 arguments skipped)

and those --add-exports flags would seem to be exactly the flags needed to solve this issue.

I was able to reproduce this in a small Minimal Example that doesn't depend on the registry.

I don't know much about the java toolchain setup or how to customize it (or where to do so if need be). Ideally if it is necessary it would be something I could do centrally. I have many different workspaces and it would be better if I didn't have to reconfigure the toolchain separately in each one.

Another potential concern is that eventually some projects will be Android based (I haven't gotten any Android to work with the bzlmod registry yet, but that's a different problem for another time if I can't crack it), so changes to the toolchain that would prevent that would be less than ideal.

Since any of the custom errorprone checks would only be run by bazel itself through its a part of the errorprone integration, maybe I just need a toolchain to use for those checks (and their tests) specifically? Still, ideally if it can be done without toolchain customization, that would be better.

Aside

Unrelated to the problem specifically, but potentially helpful to improve my understanding:

To see what would happen, I tried setting the language level higher (17) and then I got:

ERROR: D:/_bazel_out/sfuxpclr/external/rules_jvm_external~~maven~javax_maven/BUILD:26:11: Stamping the manifest of @@rules_jvm_external~~maven~javax_maven//:javax_annotation_javax_annotation_api failed: (Exit 1): AddJarManifestEntry.exe failed: error executing StampJarManifest command (from targ
et @@rules_jvm_external~~maven~javax_maven//:javax_annotation_javax_annotation_api) bazel-out\x64_windows-opt-exec-ST-13d3ddad9198\bin\external\rules_jvm_external~\private\tools\java\com\github\bazelbuild\rules_jvm_external\jar\AddJarManifestEntry.exe --source ... (remaining 5 arguments skipped)
Error: LinkageError occurred while loading main class com.github.bazelbuild.rules_jvm_external.jar.AddJarManifestEntry                                                                                                                                                                    
        java.lang.UnsupportedClassVersionError: com/github/bazelbuild/rules_jvm_external/jar/AddJarManifestEntry has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0

At first I thought this would be caused by including jars from maven that were compiled under an earlier version that then cannot be linked in. But the error message seems backwards, as "this version of the java runtime" would be the older one, and it's complaining (presumably) about my code compiled under the v17 runtime I specified. But if I specified (tool_)java_language_version=17, then where is "this" older runtime coming from? What's trying to use it?


Solution

  • Credit to Fabian on the bazel project for helping with this.

    It turned out the issue stemmed from a misunderstanding of how the add-exports and add-opens flags worked.

    1. The flags in the list that provided confusion were being passed to the JVM that ran the compiler, not the compiler.
    2. When I tried adding the flags manually as JVM flags, that didn't work as they needed to be javacopts flags.
    3. In addition, for compilation, the distinction between add-exports and add-opens becomes important as add-opens is ignored at compile time so the flags I'd copied from a query to get the list from the toolchain were not correct as the add-opens flags in that list needed to be changed to add-exports.

    With the flags added as either --javacopt flags in the bazelrc file or as javacopts on the java_library target, the build was able to succeed.