Add `--multi_release_deploy_jars`, which causes `_deploy.jar` outputs of `java_binary` to be Multi-Release jar files

see also https://openjdk.java.net/jeps/238

PiperOrigin-RevId: 437788839
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
index c79d175..83cd922 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaSemantics.java
@@ -568,7 +568,8 @@
       // Explicitly ignoring params since Bazel doesn't yet support one version
       OneVersionEnforcementLevel oneVersionEnforcementLevel,
       Artifact oneVersionAllowlistArtifact,
-      Artifact sharedArchive) {
+      Artifact sharedArchive,
+      boolean multiReleaseDeployJars) {
     return DeployArchiveBuilder.defaultSingleJarCommandLineWithoutOneVersion(
             output,
             mainClass,
@@ -578,7 +579,8 @@
             classpath,
             includeBuildData,
             compression,
-            launcher)
+            launcher,
+            /* multiReleaseDeployJars= */ multiReleaseDeployJars)
         .build();
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java
index 35b9172..5d4eb9b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/DeployArchiveBuilder.java
@@ -69,6 +69,7 @@
   private OneVersionEnforcementLevel oneVersionEnforcementLevel = OneVersionEnforcementLevel.OFF;
   @Nullable private Artifact oneVersionAllowlistArtifact;
   @Nullable private Artifact sharedArchive;
+  private boolean multiReleaseDeployJars;
 
   /** Type of compression to apply to output archive. */
   public enum Compression {
@@ -169,6 +170,11 @@
     return this;
   }
 
+  public DeployArchiveBuilder setMultiReleaseDeployJars(boolean multiReleaseDeployJars) {
+    this.multiReleaseDeployJars = multiReleaseDeployJars;
+    return this;
+  }
+
   public DeployArchiveBuilder setSharedArchive(@Nullable Artifact sharedArchive) {
     this.sharedArchive = sharedArchive;
     return this;
@@ -183,7 +189,8 @@
       NestedSet<Artifact> runtimeClasspath,
       boolean includeBuildData,
       Compression compress,
-      Artifact launcher) {
+      Artifact launcher,
+      boolean multiReleaseDeployJars) {
     return defaultSingleJarCommandLine(
         outputJar,
         javaMainClass,
@@ -195,7 +202,8 @@
         compress,
         launcher,
         OneVersionEnforcementLevel.OFF,
-        null);
+        null,
+        /* multiReleaseDeployJars= */ multiReleaseDeployJars);
   }
 
   public static CustomCommandLine.Builder defaultSingleJarCommandLine(
@@ -209,7 +217,8 @@
       Compression compress,
       Artifact launcher,
       OneVersionEnforcementLevel oneVersionEnforcementLevel,
-      @Nullable Artifact oneVersionAllowlistArtifact) {
+      @Nullable Artifact oneVersionAllowlistArtifact,
+      boolean multiReleaseDeployJars) {
 
     CustomCommandLine.Builder args = CustomCommandLine.builder();
     args.addExecPath("--output", outputJar);
@@ -253,6 +262,9 @@
         args.add("--succeed_on_found_violations");
       }
     }
+    if (multiReleaseDeployJars) {
+      args.add("--multi_release");
+    }
     return args;
   }
 
@@ -361,7 +373,8 @@
             launcher,
             oneVersionEnforcementLevel,
             oneVersionAllowlistArtifact,
-            sharedArchive);
+            sharedArchive,
+            /* multiReleaseDeployJars= */ multiReleaseDeployJars);
     if (checkDesugarDeps) {
       commandLine = CommandLine.concat(commandLine, ImmutableList.of("--check_desugar_deps"));
     }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
index 069067e..e2b6274 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
@@ -398,6 +398,7 @@
         .setOneVersionEnforcementLevel(
             javaConfig.oneVersionEnforcementLevel(),
             JavaToolchainProvider.from(ruleContext).getOneVersionAllowlist())
+        .setMultiReleaseDeployJars(javaConfig.multiReleaseDeployJars())
         .setSharedArchive(jsa)
         .build();
 
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
index 8324c17..18d7370 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
@@ -103,6 +103,7 @@
   private final boolean experimentalTurbineAnnotationProcessing;
   private final boolean experimentalEnableJspecify;
   private final boolean requireJavaPluginInfo;
+  private final boolean multiReleaseDeployJars;
 
   // TODO(dmarting): remove once we have a proper solution for #2539
   private final boolean useLegacyBazelJavaTest;
@@ -139,6 +140,7 @@
     this.runAndroidLint = javaOptions.runAndroidLint;
     this.limitAndroidLintToAndroidCompatible = javaOptions.limitAndroidLintToAndroidCompatible;
     this.requireJavaPluginInfo = javaOptions.requireJavaPluginInfo;
+    this.multiReleaseDeployJars = javaOptions.multiReleaseDeployJars;
 
     Map<String, Label> optimizers = javaOptions.bytecodeOptimizers;
     if (optimizers.size() > 1) {
@@ -341,6 +343,11 @@
   }
 
   @Override
+  public boolean multiReleaseDeployJars() {
+    return multiReleaseDeployJars;
+  }
+
+  @Override
   public String starlarkOneVersionEnforcementLevel() {
     return oneVersionEnforcementLevel().name();
   }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
index 7794ef2..cc28a8e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
@@ -552,6 +552,15 @@
   public boolean requireJavaPluginInfo;
 
   @Option(
+      name = "incompatible_multi_release_deploy_jars",
+      defaultValue = "false",
+      documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+      effectTags = {OptionEffectTag.UNKNOWN},
+      metadataTags = {OptionMetadataTag.INCOMPATIBLE_CHANGE},
+      help = "When enabled, java_binary creates Multi-Release deploy jars.")
+  public boolean multiReleaseDeployJars;
+
+  @Option(
       name = "experimental_enable_jspecify",
       defaultValue = "true",
       documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
@@ -618,6 +627,8 @@
 
     host.requireJavaPluginInfo = requireJavaPluginInfo;
 
+    host.multiReleaseDeployJars = multiReleaseDeployJars;
+
     return host;
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
index 9a9b088..5972aee 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
@@ -267,7 +267,8 @@
       Artifact launcher,
       OneVersionEnforcementLevel oneVersionEnforcementLevel,
       Artifact oneVersionAllowlistArtifact,
-      Artifact sharedArchive);
+      Artifact sharedArchive,
+      boolean multiReleaseDeployJars);
 
   /**
    * Creates the action that writes the Java executable stub script.
diff --git a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java
index d12cb1d..ab69217 100644
--- a/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java
+++ b/src/main/java/com/google/devtools/build/lib/starlarkbuildapi/java/JavaConfigurationApi.java
@@ -55,6 +55,12 @@
   String starlarkOneVersionEnforcementLevel();
 
   @StarlarkMethod(
+      name = "multi_release_deploy_jars",
+      structField = true,
+      doc = "The value of the --incompatible_multi_release_deploy_jars flag.")
+  boolean multiReleaseDeployJars();
+
+  @StarlarkMethod(
       name = "plugins",
       structField = true,
       doc = "A list containing the labels provided with --plugins, if any.")
diff --git a/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java b/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java
index eb91882..a60dfcc 100644
--- a/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java
+++ b/src/test/java/com/google/devtools/build/lib/view/java/SingleJarCommandLineTest.java
@@ -54,7 +54,8 @@
                 UNCOMPRESSED,
                 null,
                 OneVersionEnforcementLevel.OFF,
-                null)
+                null,
+                /* multiReleaseDeployJars= */ false)
             .build();
 
     assertThat(command.arguments()).doesNotContain("--exclude_build_data");
@@ -77,7 +78,8 @@
                 UNCOMPRESSED,
                 null,
                 OneVersionEnforcementLevel.OFF,
-                null)
+                null,
+                /* multiReleaseDeployJars= */ false)
             .build();
 
     assertThat(command.arguments()).contains("--exclude_build_data");
@@ -100,7 +102,8 @@
                 UNCOMPRESSED,
                 dummy,
                 OneVersionEnforcementLevel.OFF,
-                null)
+                null,
+                /* multiReleaseDeployJars= */ false)
             .build();
     assertThat(command.arguments()).contains("--java_launcher");
   }
@@ -122,7 +125,8 @@
                 COMPRESSED,
                 dummy,
                 OneVersionEnforcementLevel.OFF,
-                null)
+                null,
+                /* multiReleaseDeployJars= */ false)
             .build();
     assertThat(command.arguments()).contains("--compression");
   }
@@ -144,7 +148,8 @@
                 UNCOMPRESSED,
                 dummy,
                 OneVersionEnforcementLevel.OFF,
-                null)
+                null,
+                /* multiReleaseDeployJars= */ false)
             .build();
     assertThat(command.arguments()).doesNotContain("--compression");
   }
@@ -170,7 +175,8 @@
                 UNCOMPRESSED,
                 dummy,
                 OneVersionEnforcementLevel.WARNING,
-                dummyOneVersion)
+                dummyOneVersion,
+                /* multiReleaseDeployJars= */ false)
             .build();
     assertThat(command.arguments())
         .containsAtLeast("--enforce_one_version", "--succeed_on_found_violations");