Skip to content

Commit

Permalink
Diagnose incompatible annotation processors
Browse files Browse the repository at this point in the history
When an annotation processor is built targeting a language level that isn't supported by the Java runtime used for compilation, JavaBuilder now throws an exception with actionable information.

Example:
```
java.lang.IllegalStateException: The Java 17 runtime used to run javac is not recent enough to run the processor com.google.devtools.build.runfiles.AutoBazelRepositoryProcessor, which has been compiled targeting Java 20. Either register a Java toolchain with a newer java_runtime or, if this processor has been built with Bazel, specify a lower --tool_java_language_version.
	at com.google.devtools.build.buildjar.javac.BlazeJavaCompiler.initProcessAnnotations(BlazeJavaCompiler.java:119)
        ...
```

Work towards #17281

Closes #19548.

PiperOrigin-RevId: 570766544
Change-Id: I71a53201a63f153b2318fff0a938a6626149e02f
  • Loading branch information
fmeum authored and copybara-github committed Oct 4, 2023
1 parent 2341891 commit 09d3f06
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
Expand All @@ -70,6 +72,11 @@
*/
public class BlazeJavacMain {

private static final Pattern UNSUPPORTED_CLASS_VERSION_ERROR =
Pattern.compile(
"^(?<class>[^ ]*) has been compiled by a more recent version of the Java Runtime "
+ "\\(class file version (?<version>[4-9][0-9])\\.");

/**
* Sets up a BlazeJavaCompiler with the given plugins within the given context.
*
Expand Down Expand Up @@ -139,8 +146,23 @@ public static BlazeJavacResult compile(BlazeJavacArguments arguments) {
throw e.getCause();
}
} catch (Exception t) {
if (t.getCause() instanceof CancelRequestException) {
return BlazeJavacResult.cancelled(t.getCause().getMessage());
Throwable cause = t.getCause();
if (cause instanceof CancelRequestException) {
return BlazeJavacResult.cancelled(cause.getMessage());
}
Matcher matcher;
if (cause instanceof UnsupportedClassVersionError
&& (matcher = UNSUPPORTED_CLASS_VERSION_ERROR.matcher(cause.getMessage())).find()) {
// Java 8 corresponds to class file major version 52.
int processorVersion = Integer.parseUnsignedInt(matcher.group("version")) - 44;
errWriter.printf(
"The Java %d runtime used to run javac is not recent enough to run the processor %s, "
+ "which has been compiled targeting Java %d. Either register a Java toolchain "
+ "with a newer java_runtime or, if this processor has been built with Bazel, "
+ "specify a lower --tool_java_language_version.%n",
Runtime.version().feature(),
matcher.group("class").replace('/', '.'),
processorVersion);
}
t.printStackTrace(errWriter);
status = Status.CRASH;
Expand Down
45 changes: 45 additions & 0 deletions src/test/shell/bazel/bazel_java17_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,50 @@ EOF
expect_log "^World\$"
}

function test_incompatible_processor() {
mkdir -p pkg
# This test defines a custom Java toolchain as it relies on the availability of a runtime that is
# strictly newer than the one specified as the toolchain's java_runtime.
cat >pkg/BUILD <<EOF
load("@bazel_tools//tools/jdk:default_java_toolchain.bzl", "default_java_toolchain")
java_binary(
name = "Main",
srcs = ["Main.java"],
main_class = "com.example.Main",
# Exports an annotation processor.
deps = ["@bazel_tools//tools/java/runfiles"],
)
default_java_toolchain(
name = "java_toolchain",
source_version = "17",
target_version = "17",
java_runtime = "@bazel_tools//tools/jdk:remotejdk_17",
)
EOF

cat >pkg/Main.java <<'EOF'
package com.example;
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
EOF

# Specify a --tool_java_language_version higher than any tested runtime.
bazel build //pkg:Main \
--extra_toolchains=//pkg:java_toolchain_definition \
--java_language_version=17 \
--java_runtime_version=remotejdk_17 \
--tool_java_language_version=20 \
--tool_java_runtime_version=remotejdk_20 \
&>"${TEST_log}" && fail "Expected build to fail"

expect_log "The Java 17 runtime used to run javac is not recent enough to run the processor " \
"com\.google\.devtools\.build\.runfiles\.AutoBazelRepositoryProcessor, which has been " \
"compiled targeting Java 20\. Either register a Java toolchain with a newer java_runtime " \
"or, if this processor has been built with Bazel, specify a lower " \
"--tool_java_language_version\."
}

run_suite "Tests Java 17 language features"

0 comments on commit 09d3f06

Please sign in to comment.